Compare commits

...

174 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
黑化肥挥发会发灰 9ed5fbd2e3
优化 select.form-control 样式遮盖选中项文字 2022-01-20 03:13:19 +00:00
154 changed files with 1983 additions and 36893 deletions

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/其他):?
- 报错信息:?

2
.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/*
@ -16,3 +15,4 @@ composer.lock
.svn .svn
.vscode .vscode
node_modules node_modules
.user.ini

View File

@ -24,12 +24,10 @@ FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。
* 多语言支持,服务端及客户端支持 * 多语言支持,服务端及客户端支持
* 支持大文件分片上传、剪切板粘贴上传、拖拽上传,进度条显示,图片上传前压缩 * 支持大文件分片上传、剪切板粘贴上传、拖拽上传,进度条显示,图片上传前压缩
* 支持表格固定列、固定表头、跨页选择、Excel导出、模板渲染等功能 * 支持表格固定列、固定表头、跨页选择、Excel导出、模板渲染等功能
* 强大的第三方应用模块支持([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)、[B2C商城](https://www.fastadmin.net/store/shopro.html)、[B2B2C商城](https://www.fastadmin.net/store/wanlshop.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))
* 支持CMS、博客、知识付费问答无缝整合[Xunsearch全文搜索](https://www.fastadmin.net/store/xunsearch.html)
* 第三方小程序支持([CMS小程序](https://www.fastadmin.net/store/cms.html)、[预订小程序](https://www.fastadmin.net/store/ball.html)、[问答小程序](https://www.fastadmin.net/store/ask.html)、[点餐小程序](https://www.fastadmin.net/store/unidrink.html)、[B2C小程序](https://www.fastadmin.net/store/shopro.html)、[B2B2C小程序](https://www.fastadmin.net/store/wanlshop.html)、[博客小程序](https://www.fastadmin.net/store/blog.html))
* 整合第三方短信接口(阿里云、腾讯云短信) * 整合第三方短信接口(阿里云、腾讯云短信)
* 无缝整合第三方云存储(七牛云、阿里云OSS、又拍云)功能,支持云储存分片上传 * 无缝整合第三方云存储(七牛云、阿里云OSS、腾讯云存储、又拍云)功能,支持云储存分片上传
* 第三方富文本编辑器支持(Summernote、Kindeditor、百度编辑器) * 第三方富文本编辑器支持(Summernote、百度编辑器)
* 第三方登录(QQ、微信、微博)整合 * 第三方登录(QQ、微信、微博)整合
* 第三方支付(微信、支付宝)无缝整合微信支持PC端扫码支付 * 第三方支付(微信、支付宝)无缝整合微信支持PC端扫码支付
* 丰富的插件应用市场 * 丰富的插件应用市场
@ -55,9 +53,7 @@ https://demo.fastadmin.net
在使用中有任何问题,请使用以下联系方式联系我们 在使用中有任何问题,请使用以下联系方式联系我们
交流社区: 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
@ -81,7 +77,7 @@ Nice-validator: https://validator.niceue.com
SelectPage: https://github.com/TerryZ/SelectPage SelectPage: https://github.com/TerryZ/SelectPage
Layer: https://layer.layui.com Layer: https://layuion.com/layer/
DropzoneJS: https://www.dropzonejs.com DropzoneJS: https://www.dropzonejs.com
@ -92,6 +88,6 @@ FastAdmin遵循Apache2开源协议发布并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。 本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2017-2022 by FastAdmin (https://www.fastadmin.net) 版权所有Copyright © 2017-2024 by FastAdmin (https://www.fastadmin.net)
All rights reserved。 All rights reserved。

View File

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

View File

@ -15,7 +15,6 @@ use think\exception\PDOException;
class Addon extends Command class Addon extends Command
{ {
protected function configure() protected function configure()
{ {
$this $this
@ -33,6 +32,7 @@ class Addon extends Command
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) {
@ -82,7 +82,6 @@ class Addon extends Command
$createTableSql = $result[0]['Create Table']; $createTableSql = $result[0]['Create Table'];
} }
} catch (PDOException $e) { } catch (PDOException $e) {
} }
$data = [ $data = [
@ -177,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'));
} }
@ -340,5 +339,4 @@ class Addon extends Command
{ {
return __DIR__ . '/Addon/stubs/' . $name . '.stub'; return __DIR__ . '/Addon/stubs/' . $name . '.stub';
} }
} }

View File

@ -3,7 +3,7 @@
return [ return [
[ [
//配置唯一标识 //配置唯一标识
'name' => 'usernmae', 'name' => 'username',
//显示的标题 //显示的标题
'title' => '用户名', 'title' => '用户名',
//类型 //类型

View File

@ -98,13 +98,13 @@ class Api extends Command
foreach ($files as $name => $file) { foreach ($files as $name => $file) {
if (!$file->isDir() && $file->getExtension() == 'php') { if (!$file->isDir() && $file->getExtension() == 'php') {
$filePath = $file->getRealPath(); $filePath = $file->getRealPath();
$classes[] = $this->get_class_from_file($filePath); $classes[] = $this->getClassFromFile($filePath);
} }
} }
} else { } else {
foreach ($controller as $index => $item) { foreach ($controller as $index => $item) {
$filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php'; $filePath = $moduleDir . Config::get('url_controller_layer') . DS . $item . '.php';
$classes[] = $this->get_class_from_file($filePath); $classes[] = $this->getClassFromFile($filePath);
} }
} }
@ -129,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

@ -88,11 +88,17 @@ 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' => $params['type'] ?? 'string', 'type' => $params['type'] ?? 'string',
'inputtype' => $inputtype,
'sample' => $params['sample'] ?? '', 'sample' => $params['sample'] ?? '',
'required' => $params['required'] ?? true, 'required' => $params['required'] ?? true,
'description' => $params['description'] ?? '', 'description' => $params['description'] ?? '',

View File

@ -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">
@ -137,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">
@ -295,7 +295,7 @@
{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>
@ -314,7 +314,7 @@
{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 /}
@ -401,10 +401,10 @@
</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) {

View File

@ -152,7 +152,7 @@ class Crud extends Command
/** /**
* JSON后缀 * JSON后缀
*/ */
protected $jsonSuffix = ['json']; protected $jsonSuffix = ['json', 'array'];
/** /**
* 标签后缀 * 标签后缀
@ -435,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 = [];
//检查关联表 //检查关联表
@ -466,7 +469,7 @@ class Crud extends Command
} }
} }
$relationTableInfo = $relationTableInfo[0]; $relationTableInfo = $relationTableInfo[0];
$relationModel = isset($relationModels[$index]) ? $relationModels[$index] : ''; $relationModel = $relationModels[$index] ?? '';
list($relationNamespace, $relationName, $relationFile) = $this->getModelData($modelModuleName, $relationModel, $relationName); list($relationNamespace, $relationName, $relationFile) = $this->getModelData($modelModuleName, $relationModel, $relationName);
@ -666,8 +669,8 @@ class Crud extends Command
//如果是关联模型 //如果是关联模型
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 . ']');
@ -676,8 +679,8 @@ class Crud extends Command
throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']'); throw new Exception('table [' . $modelTableName . '] must be contain field [' . $relationPrimaryKey . ']');
} }
} elseif ($relation['relationMode'] == 'belongsto') { } 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 . ']');
} }
@ -685,8 +688,8 @@ class Crud extends Command
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') { } elseif ($relation['relationMode'] == 'hasmany') {
$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 . ']');
} }
@ -712,6 +715,7 @@ class Crud extends Command
$headingHtml = '{:build_heading()}'; $headingHtml = '{:build_heading()}';
$controllerImport = ''; $controllerImport = '';
$importHtml = ''; $importHtml = '';
$multipleHtml = '';
$recyclebinHtml = ''; $recyclebinHtml = '';
if ($import) { if ($import) {
@ -878,7 +882,7 @@ class Crud extends Command
$formEditElement = Form::input('text', $fieldName, $editValue, $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']) && !isset($itemArr['value']) && count($itemArr) > 0 ? 'fieldlist-template' : 'fieldlist'; $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';
$theadListArr = $tbodyListArr = []; $theadListArr = $tbodyListArr = [];
@ -900,6 +904,12 @@ class Crud extends Command
$cssClassArr[] = 'selectpage'; $cssClassArr[] = 'selectpage';
$selectpageTable = substr($field, 0, strripos($field, '_')); $selectpageTable = substr($field, 0, strripos($field, '_'));
$selectpageField = ''; $selectpageField = '';
foreach ($relations as $index => $relation) {
if ($relation['relationForeignKey'] === $field) {
$selectpageTable = substr($relation['relationTableName'], strlen($prefix));
break;
}
}
$selectpageController = str_replace('_', '/', $selectpageTable); $selectpageController = str_replace('_', '/', $selectpageTable);
$attrArr['data-source'] = $selectpageController . "/index"; $attrArr['data-source'] = $selectpageController . "/index";
//如果是类型表需要特殊处理下 //如果是类型表需要特殊处理下
@ -930,7 +940,6 @@ class Crud extends Command
} }
} }
} catch (\Exception $e) { } catch (\Exception $e) {
} }
if (!$selectpageField) { if (!$selectpageField) {
foreach ($this->fieldSelectpageMap as $m => $n) { foreach ($this->fieldSelectpageMap as $m => $n) {
@ -957,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) {
@ -987,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;
@ -1041,7 +1056,7 @@ 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);
} }
} }
} }
@ -1069,7 +1084,7 @@ class Crud extends Command
} }
//表注释 //表注释
$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 = '';
@ -1114,6 +1129,7 @@ class Crud extends Command
'controllerIndex' => '', 'controllerIndex' => '',
'recyclebinJs' => '', 'recyclebinJs' => '',
'headingHtml' => $headingHtml, 'headingHtml' => $headingHtml,
'multipleHtml' => $multipleHtml,
'importHtml' => $importHtml, 'importHtml' => $importHtml,
'recyclebinHtml' => $recyclebinHtml, 'recyclebinHtml' => $recyclebinHtml,
'visibleFieldList' => $fields ? "\$row->visible(['" . implode("','", array_filter(in_array($priKey, explode(',', $fields)) ? explode(',', $fields) : explode(',', $priKey . ',' . $fields))) . "']);" : '', 'visibleFieldList' => $fields ? "\$row->visible(['" . implode("','", array_filter(in_array($priKey, explode(',', $fields)) ? explode(',', $fields) : explode(',', $priKey . ',' . $fields))) . "']);" : '',
@ -1461,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) {
@ -1469,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;
} }
} }
@ -1526,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) {
@ -1544,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']) {
@ -1688,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 = '';
@ -1728,7 +1748,7 @@ EOD;
$noSearchFiles = ['file$', 'files$', 'image$', 'images$', '^weigh$']; $noSearchFiles = ['file$', 'files$', 'image$', 'images$', '^weigh$'];
if (preg_match("/" . implode('|', $noSearchFiles) . "/i", $field)) { if (preg_match("/" . implode('|', $noSearchFiles) . "/i", $field)) {
$html .= ", operate: false"; $html .= ", operate: false";
} else if (in_array($datatype, ['varchar'])) { } elseif (in_array($datatype, ['varchar'])) {
$html .= ", operate: 'LIKE'"; $html .= ", operate: 'LIKE'";
} }
@ -1740,6 +1760,10 @@ EOD;
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

@ -5,7 +5,6 @@
<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-primary 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

@ -5,7 +5,6 @@
<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-primary 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,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

@ -12,13 +12,7 @@
<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>
{%importHtml%} {%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>

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

@ -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

@ -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,

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,7 +86,7 @@ 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);
@ -182,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 utf8mb4 COLLATE utf8mb4_unicode_ci;"); $pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;");
// 连接install命令中指定的数据库 // 连接install命令中指定的数据库
$instance = Db::connect([ $instance = Db::connect([
@ -309,8 +309,8 @@ class Install extends Command
//数据库配置文件 //数据库配置文件
$dbConfigFile = APP_PATH . 'database.php'; $dbConfigFile = APP_PATH . 'database.php';
if (version_compare(PHP_VERSION, '7.1.0', '<')) { if (version_compare(PHP_VERSION, '7.4.0', '<')) {
throw new Exception(__("The current version %s is too low, please use PHP 7.1 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: 2020-06-11 22:11:09 Date: 2024-09-03 15:05:25
*/ */
SET FOREIGN_KEY_CHECKS = 0; SET FOREIGN_KEY_CHECKS = 0;
@ -8,7 +8,6 @@ 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) DEFAULT '' COMMENT '用户名', `username` varchar(20) DEFAULT '' COMMENT '用户名',
@ -27,19 +26,18 @@ CREATE TABLE `fa_admin` (
`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=utf8mb4 COLLATE utf8mb4_unicode_ci 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', '', '', '/assets/img/avatar.png', 'admin@admin.com', '', 0, 1491635035, '127.0.0.1',1491635035, 1491635035, '', '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',
@ -52,12 +50,11 @@ CREATE TABLE `fa_admin_log` (
`createtime` bigint(16) 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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='管理员日志表'; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='管理员日志表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_area -- Table structure for fa_area
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_area`;
CREATE TABLE `fa_area` ( CREATE TABLE `fa_area` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`pid` int(10) DEFAULT NULL COMMENT '父id', `pid` int(10) DEFAULT NULL COMMENT '父id',
@ -73,20 +70,19 @@ CREATE TABLE `fa_area` (
`lat` varchar(100) DEFAULT NULL COMMENT '纬度', `lat` varchar(100) DEFAULT NULL COMMENT '纬度',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `pid` (`pid`) KEY `pid` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='地区表'; ) 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 '类别', `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) DEFAULT '' COMMENT '物理路径', `url` varchar(255) DEFAULT '' COMMENT '物理路径',
`imagewidth` varchar(30) DEFAULT '' COMMENT '宽度', `imagewidth` int(10) unsigned DEFAULT 0 COMMENT '宽度',
`imageheight` varchar(30) DEFAULT '' COMMENT '高度', `imageheight` int(10) unsigned DEFAULT 0 COMMENT '高度',
`imagetype` varchar(30) 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 '文件名称', `filename` varchar(100) DEFAULT '' COMMENT '文件名称',
@ -99,7 +95,7 @@ CREATE TABLE `fa_attachment` (
`storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置', `storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置',
`sha1` varchar(40) DEFAULT '' COMMENT '文件 sha1编码', `sha1` varchar(40) DEFAULT '' COMMENT '文件 sha1编码',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='附件表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='附件表';
-- ---------------------------- -- ----------------------------
-- Records of fa_attachment -- Records of fa_attachment
@ -111,7 +107,6 @@ 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 '父组别',
@ -121,7 +116,7 @@ CREATE TABLE `fa_auth_group` (
`updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间', `updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
`status` varchar(30) DEFAULT '' COMMENT '状态', `status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='分组表'; ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='分组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_group -- Records of fa_auth_group
@ -137,14 +132,13 @@ 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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='权限分组表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='权限分组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_group_access -- Records of fa_auth_group_access
@ -156,7 +150,6 @@ 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为权限节点',
@ -180,7 +173,7 @@ CREATE TABLE `fa_auth_rule` (
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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='节点表'; ) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='节点表';
-- ---------------------------- -- ----------------------------
-- Records of fa_auth_rule -- Records of fa_auth_rule
@ -273,7 +266,6 @@ 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',
@ -292,7 +284,7 @@ CREATE TABLE `fa_category` (
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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='分类表'; ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='分类表';
-- ---------------------------- -- ----------------------------
-- Records of fa_category -- Records of fa_category
@ -316,7 +308,6 @@ 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) DEFAULT '' COMMENT '变量名', `name` varchar(30) DEFAULT '' COMMENT '变量名',
@ -332,7 +323,7 @@ CREATE TABLE `fa_config` (
`setting` 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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='系统配置'; ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='系统配置';
-- ---------------------------- -- ----------------------------
-- Records of fa_config -- Records of fa_config
@ -345,23 +336,22 @@ INSERT INTO `fa_config` VALUES (4, 'version', 'basic', 'Version', '如果静态
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', '[\"请选择\",\"SMTP\"]', '', '', ''); 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', '[\"无\",\"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\"}', '', '', '', ''); 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) DEFAULT '' COMMENT '事件', `event` varchar(30) DEFAULT '' COMMENT '事件',
@ -371,12 +361,11 @@ CREATE TABLE `fa_ems` (
`ip` varchar(30) DEFAULT '' COMMENT 'IP', `ip` varchar(30) DEFAULT '' COMMENT 'IP',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci 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) DEFAULT '' COMMENT '事件', `event` varchar(30) DEFAULT '' COMMENT '事件',
@ -386,12 +375,11 @@ CREATE TABLE `fa_sms` (
`ip` varchar(30) DEFAULT '' COMMENT 'IP', `ip` varchar(30) DEFAULT '' COMMENT 'IP',
`createtime` bigint(16) unsigned DEFAULT '0' COMMENT '创建时间', `createtime` bigint(16) unsigned DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci 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',
`user_id` int(10) DEFAULT '0' COMMENT '会员ID', `user_id` int(10) DEFAULT '0' COMMENT '会员ID',
@ -411,7 +399,8 @@ CREATE TABLE `fa_test` (
`keywords` varchar(255) DEFAULT '' COMMENT '关键字', `keywords` varchar(255) DEFAULT '' COMMENT '关键字',
`description` varchar(255) DEFAULT '' COMMENT '描述', `description` varchar(255) DEFAULT '' COMMENT '描述',
`city` varchar(100) DEFAULT '' COMMENT '省市', `city` varchar(100) DEFAULT '' COMMENT '省市',
`json` varchar(255) DEFAULT NULL COMMENT '配置:key=名称,value=值', `array` varchar(255) DEFAULT '' COMMENT '数组:value=值',
`json` varchar(255) DEFAULT '' COMMENT '配置:key=名称,value=值',
`multiplejson` varchar(1500) DEFAULT '' COMMENT '二维数组:title=标题,intro=介绍,author=作者,age=年龄', `multiplejson` varchar(1500) DEFAULT '' COMMENT '二维数组:title=标题,intro=介绍,author=作者,age=年龄',
`price` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '价格', `price` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '价格',
`views` int(10) unsigned DEFAULT '0' COMMENT '点击', `views` int(10) unsigned DEFAULT '0' COMMENT '点击',
@ -429,19 +418,18 @@ CREATE TABLE `fa_test` (
`status` enum('normal','hidden') DEFAULT 'normal' COMMENT '状态', `status` enum('normal','hidden') DEFAULT 'normal' COMMENT '状态',
`state` enum('0','1','2') 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=utf8mb4 COLLATE utf8mb4_unicode_ci 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, 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\":\"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'); 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',
@ -464,6 +452,7 @@ CREATE TABLE `fa_user` (
`logintime` bigint(16) DEFAULT NULL COMMENT '登录时间', `logintime` bigint(16) DEFAULT NULL COMMENT '登录时间',
`loginip` varchar(50) 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 '失败次数',
`loginfailuretime` bigint(16) DEFAULT NULL COMMENT '最后登录失败时间',
`joinip` varchar(50) DEFAULT '' COMMENT '加入IP', `joinip` varchar(50) DEFAULT '' COMMENT '加入IP',
`jointime` bigint(16) DEFAULT NULL COMMENT '加入时间', `jointime` bigint(16) DEFAULT NULL COMMENT '加入时间',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
@ -475,19 +464,18 @@ CREATE TABLE `fa_user` (
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=utf8mb4 COLLATE utf8mb4_unicode_ci 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', '', '', 'admin@163.com', '13888888888', '', 0, 0, '2017-04-08', '', 0, 0, 1, 1, 1491635035, 1491635035, '127.0.0.1', 0, '127.0.0.1', 1491635035, 0, 1491635035, '', '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 '组名',
@ -496,7 +484,7 @@ CREATE TABLE `fa_user_group` (
`updatetime` bigint(16) 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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='会员组表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员组表';
-- ---------------------------- -- ----------------------------
-- Records of fa_user_group -- Records of fa_user_group
@ -508,7 +496,6 @@ 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',
@ -518,12 +505,11 @@ CREATE TABLE `fa_user_money_log` (
`memo` varchar(255) DEFAULT '' COMMENT '备注', `memo` varchar(255) DEFAULT '' COMMENT '备注',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci 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',
@ -536,7 +522,7 @@ CREATE TABLE `fa_user_rule` (
`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=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='会员规则表'; ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员规则表';
-- ---------------------------- -- ----------------------------
-- Records of fa_user_rule -- Records of fa_user_rule
@ -559,7 +545,6 @@ 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',
@ -569,24 +554,22 @@ CREATE TABLE `fa_user_score_log` (
`memo` varchar(255) DEFAULT '' COMMENT '备注', `memo` varchar(255) DEFAULT '' COMMENT '备注',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci 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` bigint(16) DEFAULT NULL COMMENT '创建时间', `createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`expiretime` bigint(16) DEFAULT NULL COMMENT '过期时间', `expiretime` bigint(16) DEFAULT NULL COMMENT '过期时间',
PRIMARY KEY (`token`) PRIMARY KEY (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='会员Token表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='会员Token表';
-- ---------------------------- -- ----------------------------
-- Table structure for fa_version -- Table structure for fa_version
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `fa_version`;
CREATE TABLE `fa_version` ( CREATE TABLE `fa_version` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`oldversion` varchar(30) DEFAULT '' COMMENT '旧版本号', `oldversion` varchar(30) DEFAULT '' COMMENT '旧版本号',
@ -600,6 +583,6 @@ CREATE TABLE `fa_version` (
`weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重', `weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重',
`status` varchar(30) DEFAULT '' COMMENT '状态', `status` varchar(30) DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='版本表'; ) 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

@ -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 () {

View File

@ -20,14 +20,14 @@ 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-30位数字、字母、下划线组合', 'Please input correct username' => '用户名只能由3-30位数字、字母、下划线组合',
'Please input correct password' => '密码长度必须在6-30位之间不能包含空格', 'Please input correct password' => '密码长度必须在6-30位之间不能包含空格',
'Password is too weak' => '密码太简单,请重新输入', 'Password is too weak' => '密码太简单,请重新输入',
'The two passwords you entered did not match' => '两次输入的密码不一致', 'The two passwords you entered did not match' => '两次输入的密码不一致',
'Please input correct website' => '网站名称输入不正确', 'Please input correct website' => '网站名称输入不正确',
'The current version %s is too low, please use PHP 7.1 or higher' => '当前版本%s过低请使用PHP7.1以上版本', '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' => '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装',

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

@ -18,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);
} }
} }
@ -39,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>';
} }
@ -60,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>';
} }
@ -121,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];

View File

@ -95,19 +95,24 @@ class Addon extends Backend
} }
$tips = []; $tips = [];
$groupList = []; $groupList = [];
$ungroupList = [];
foreach ($config as $index => &$item) { foreach ($config as $index => &$item) {
//如果有设置分组 //如果有设置分组
if (isset($item['group']) && $item['group']) { if (isset($item['group']) && $item['group']) {
if (!in_array($item['group'], $groupList)) { if (!in_array($item['group'], $groupList)) {
$groupList["custom" . (count($groupList) + 1)] = $item['group']; $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]);
} }
} }
$groupList['other'] = '其它'; if ($ungroupList) {
$groupList['other'] = '其它';
}
$this->view->assign("groupList", $groupList); $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';
@ -230,6 +235,7 @@ class Addon extends Backend
$uid = $this->request->post("uid"); $uid = $this->request->post("uid");
$token = $this->request->post("token"); $token = $this->request->post("token");
$faversion = $this->request->post("faversion"); $faversion = $this->request->post("faversion");
$force = $this->request->post("force");
if (!$uid || !$token) { if (!$uid || !$token) {
throw new Exception(__('Please login and try to install')); throw new Exception(__('Please login and try to install'));
} }
@ -238,7 +244,7 @@ class Addon extends Backend
'token' => $token, 'token' => $token,
'faversion' => $faversion 'faversion' => $faversion
]; ];
$info = Service::local($file, $extend); $info = Service::local($file, $extend, $force);
} 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) {
@ -266,15 +272,17 @@ class Addon extends Backend
$info = []; $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
]; ];
//调用更新的方法 //调用更新的方法
$info = Service::upgrade($name, $extend); $info = Service::upgrade($name, $extend);
@ -317,9 +325,8 @@ 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 = $this->getAddonList();
$filter = (array)json_decode($filter, true); $filter = (array)json_decode($filter, true);
$addons = get_addon_list(); $addons = get_addon_list();
@ -337,7 +344,6 @@ class Addon extends Backend
$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'] = [];
@ -441,8 +447,11 @@ class Addon extends Backend
} catch (\Exception $e) { } catch (\Exception $e) {
} }
$rows = isset($json['rows']) ? $json['rows'] : []; $rows = $json['rows'] ?? [];
foreach ($rows as $index => $row) { foreach ($rows as $index => $row) {
if (!isset($row['name'])) {
continue;
}
$onlineaddons[$row['name']] = $row; $onlineaddons[$row['name']] = $row;
} }
Cache::set("onlineaddons", $onlineaddons, 600); Cache::set("onlineaddons", $onlineaddons, 600);

View File

@ -11,6 +11,7 @@ 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\Response;
use think\Validate; use think\Validate;
@ -38,7 +39,7 @@ class Ajax extends Backend
*/ */
public function lang() public function lang()
{ {
$this->request->get(['callback' => 'define']);
$header = ['Content-Type' => 'application/javascript']; $header = ['Content-Type' => 'application/javascript'];
if (!config('app_debug')) { if (!config('app_debug')) {
$offset = 30 * 60 * 60 * 24; // 缓存一个月 $offset = 30 * 60 * 60 * 24; // 缓存一个月
@ -47,9 +48,20 @@ class Ajax extends Backend
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; $header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
} }
$controllername = $this->request->get('controllername');
$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);
//存在对应的类才加载
if (class_exists($className)) {
$this->loadlang($controllername);
}
return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]); return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
} }
@ -59,8 +71,10 @@ class Ajax extends Backend
public function upload() public function upload()
{ {
Config::set('default_return_type', 'json'); Config::set('default_return_type', 'json');
//必须设定cdnurl为空,否则cdnurl函数计算错误
Config::set('upload.cdnurl', ''); //必须还原upload配置,否则分片及cdnurl函数计算错误
Config::load(APP_PATH . 'extra/upload.php', 'upload');
$chunkid = $this->request->post("chunkid"); $chunkid = $this->request->post("chunkid");
if ($chunkid) { if ($chunkid) {
if (!Config::get('upload.chunking')) { if (!Config::get('upload.chunking')) {
@ -273,18 +287,18 @@ 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'] : ''; $city = isset($params['city']) ? $params['city'] : null;
} else { } else {
$province = $this->request->get('province', ''); $province = $this->request->get('province');
$city = $this->request->get('city', ''); $city = $this->request->get('city');
} }
$where = ['pid' => 0, 'level' => 1]; $where = ['pid' => 0, 'level' => 1];
$provincelist = null; $provincelist = null;
if ($province !== '') { if ($province !== null) {
$where['pid'] = $province; $where['pid'] = $province;
$where['level'] = 2; $where['level'] = 2;
if ($city !== '') { if ($city !== null) {
$where['pid'] = $city; $where['pid'] = $city;
$where['level'] = 3; $where['level'] = 3;
} }

View File

@ -44,7 +44,6 @@ class Index extends Backend
'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()) {
@ -66,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 = [
@ -95,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]);
@ -113,6 +115,7 @@ class Index extends Backend
} }
$background = Config::get('fastadmin.login_background'); $background = Config::get('fastadmin.login_background');
$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);

View File

@ -129,7 +129,7 @@ class Admin extends Backend
exception(__("Please input correct password")); exception(__("Please input correct password"));
} }
$params['salt'] = Random::alnum(); $params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']); $params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
$params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。 $params['avatar'] = '/assets/img/avatar.png'; //设置新管理员默认头像。
$result = $this->model->validate('Admin.add')->save($params); $result = $this->model->validate('Admin.add')->save($params);
if ($result === false) { if ($result === false) {
@ -183,7 +183,7 @@ class Admin extends Backend
exception(__("Please input correct password")); exception(__("Please input correct password"));
} }
$params['salt'] = Random::alnum(); $params['salt'] = Random::alnum();
$params['password'] = md5(md5($params['password']) . $params['salt']); $params['password'] = $this->auth->getEncryptPassword($params['password'], $params['salt']);
} else { } else {
unset($params['password'], $params['salt']); unset($params['password'], $params['salt']);
} }
@ -192,7 +192,7 @@ class Admin extends Backend
$adminValidate->rule([ $adminValidate->rule([
'username' => 'require|regex:\w{3,30}|unique:admin,username,' . $row->id, 'username' => 'require|regex:\w{3,30}|unique:admin,username,' . $row->id,
'email' => 'require|email|unique:admin,email,' . $row->id, 'email' => 'require|email|unique:admin,email,' . $row->id,
'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id, 'mobile' => 'regex:1[3-9]\d{9}|unique:admin,mobile,' . $row->id,
'password' => 'regex:\S{32}', 'password' => 'regex:\S{32}',
]); ]);
$result = $row->validate('Admin.edit')->save($params); $result = $row->validate('Admin.edit')->save($params);

View File

@ -44,9 +44,16 @@ class Adminlog extends Backend
$this->request->filter(['strip_tags', 'trim']); $this->request->filter(['strip_tags', 'trim']);
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$isSuperAdmin = $this->auth->isSuperAdmin();
$childrenAdminIds = $this->childrenAdminIds;
$list = $this->model $list = $this->model
->where($where) ->where($where)
->where('admin_id', 'in', $this->childrenAdminIds) ->where(function ($query) use ($isSuperAdmin, $childrenAdminIds) {
if (!$isSuperAdmin) {
$query->where('admin_id', 'in', $childrenAdminIds);
}
})
->field('content,useragent', true)
->order($sort, $order) ->order($sort, $order)
->paginate($limit); ->paginate($limit);
@ -66,8 +73,10 @@ class Adminlog extends Backend
if (!$row) { if (!$row) {
$this->error(__('No Results were found')); $this->error(__('No Results were found'));
} }
if (!$row['admin_id'] || !in_array($row['admin_id'], $this->childrenAdminIds)) { if (!$this->auth->isSuperAdmin()) {
$this->error(__('You have no permission')); 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();
@ -101,7 +110,15 @@ class Adminlog extends Backend
} }
$ids = $ids ? $ids : $this->request->post("ids"); $ids = $ids ? $ids : $this->request->post("ids");
if ($ids) { if ($ids) {
$adminList = $this->model->where('id', 'in', $ids)->where('admin_id', 'in', $this->childrenAdminIds)->select(); $isSuperAdmin = $this->auth->isSuperAdmin();
$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) { if ($adminList) {
$deleteIds = []; $deleteIds = [];
foreach ($adminList as $k => $v) { foreach ($adminList as $k => $v) {
@ -126,8 +143,4 @@ class Adminlog extends Backend
$this->error(); $this->error();
} }
public function selectpage()
{
return parent::selectpage();
}
} }

View File

@ -36,7 +36,7 @@ class Rule extends Backend
$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) {

View File

@ -74,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

@ -32,7 +32,7 @@ class Rule extends Backend
$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) {

View File

@ -24,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;
} }
/** /**

View File

@ -4,6 +4,8 @@ return [
'User id' => '会员ID', 'User id' => '会员ID',
'Username' => '用户名', 'Username' => '用户名',
'Nickname' => '昵称', 'Nickname' => '昵称',
'Mobile' => '手机',
'Email' => '邮箱',
'Password' => '密码', 'Password' => '密码',
'Sign up' => '注 册', 'Sign up' => '注 册',
'Sign in' => '登 录', 'Sign in' => '登 录',
@ -123,6 +125,8 @@ return [
'%d year%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' => '还原全部',

View File

@ -14,11 +14,8 @@ return [
'Refresh addon cache' => '刷新插件缓存', 'Refresh addon cache' => '刷新插件缓存',
'Userinfo' => '会员信息', 'Userinfo' => '会员信息',
'Reload authorization' => '刷新授权', 'Reload authorization' => '刷新授权',
'Online store' => '在线商店',
'Local addon' => '本地插件', 'Local addon' => '本地插件',
'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作', 'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作',
'Login tips' => '此处登录账号为<a href="https://www.fastadmin.net" target="_blank">FastAdmin官网账号</a>',
'Logined tips' => '你好!%s<br />当前你已经登录,将同步保存你的购买记录',
'Pay tips' => '扫码支付后如果仍然无法安装,请不要重复支付,请稍后再重试安装!', 'Pay tips' => '扫码支付后如果仍然无法安装,请不要重复支付,请稍后再重试安装!',
'Pay successful tips' => '购买成功!请点击继续安装按钮完成安装!', 'Pay successful tips' => '购买成功!请点击继续安装按钮完成安装!',
'Pay click tips' => '请点击这里在新窗口中进行支付!', 'Pay click tips' => '请点击这里在新窗口中进行支付!',
@ -26,8 +23,7 @@ return [
'Upgrade tips' => '确认升级<b>《%s》</b><p class="text-danger">1、请务必做好代码和数据库备份备份备份<br>2、升级后如出现冗余数据请根据需要移除即可!<br>3、不建议在生产环境升级请在本地完成升级测试</p>如有重要数据请备份后再操作!', 'Upgrade tips' => '确认升级<b>《%s》</b><p class="text-danger">1、请务必做好代码和数据库备份备份备份<br>2、升级后如出现冗余数据请根据需要移除即可!<br>3、不建议在生产环境升级请在本地完成升级测试</p>如有重要数据请备份后再操作!',
'Offline installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!', 'Offline installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!',
'Online installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!', 'Online installed tips' => '安装成功!清除浏览器缓存和框架缓存后生效!',
'Not login tips' => '你当前未登录FastAdmin请登录后操作', 'Please login and try to install' => '请登录FastAdmin后再进行本地安装',
'Please login and try to install' => '请登录FastAdmin后再进行离线安装',
'Not installed tips' => '请安装后再访问插件前台页面!', 'Not installed tips' => '请安装后再访问插件前台页面!',
'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!', 'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!',
'New version tips' => '发现新版本:%s 点击查看更新日志', 'New version tips' => '发现新版本:%s 点击查看更新日志',
@ -37,6 +33,7 @@ return [
'Store not available tips' => '插件市场暂不可用,是否切换到本地插件?', 'Store not available tips' => '插件市场暂不可用,是否切换到本地插件?',
'Switch to the local' => '切换到本地插件', 'Switch to the local' => '切换到本地插件',
'try to reload' => '重新尝试加载', 'try to reload' => '重新尝试加载',
'Please disable addon first' => '请先禁用插件再进行操作',
'Please disable the add before trying to upgrade' => '请先禁用插件再进行升级', 'Please disable the add before trying to upgrade' => '请先禁用插件再进行升级',
'Please disable the add before trying to uninstall' => '请先禁用插件再进行卸载', 'Please disable the add before trying to uninstall' => '请先禁用插件再进行卸载',
'Login now' => '立即登录', 'Login now' => '立即登录',
@ -80,7 +77,6 @@ return [
'Enable' => '启用', 'Enable' => '启用',
'Your username or email' => '你的手机号、用户名或邮箱', 'Your username or email' => '你的手机号、用户名或邮箱',
'Your password' => '你的密码', 'Your password' => '你的密码',
'Login FastAdmin' => '登录',
'Login' => '登录', 'Login' => '登录',
'Logout' => '退出登录', 'Logout' => '退出登录',
'Register' => '注册账号', 'Register' => '注册账号',

View File

@ -2,7 +2,7 @@
return [ return [
'Url' => '链接', 'Url' => '链接',
'Userame' => '用户名', 'Username' => '用户名',
'Createtime' => '操作时间', 'Createtime' => '操作时间',
'Click to edit' => '点击编辑', 'Click to edit' => '点击编辑',
'Admin log' => '操作日志', 'Admin log' => '操作日志',

View File

@ -25,6 +25,8 @@ return [
'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' => '用户名或密码不正确',
@ -60,5 +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', '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,7 +63,8 @@ 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;
} }
@ -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 . config('token.key'))) { 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 . config('token.key')); $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 * 7);
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,13 +228,19 @@ 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->logined = false; //重置登录状态
Session::delete("admin");
Cookie::delete("keeplogin");
return false; return false;
} }
} }
@ -284,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'] === '*') {
@ -316,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) {
@ -363,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;
@ -389,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];
@ -419,7 +472,7 @@ class Auth extends \fast\Auth
->column('name,pid'); ->column('name,pid');
$pidArr = array_unique(array_filter(array_column($ruleList, 'pid'))); $pidArr = array_unique(array_filter(array_column($ruleList, 'pid')));
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,7 +483,7 @@ class Auth extends \fast\Auth
} }
$v['icon'] = $v['icon'] . ' fa-fw'; $v['icon'] = $v['icon'] . ' fa-fw';
$v['url'] = isset($v['url']) && $v['url'] ? $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['title'] = __($v['title']); $v['title'] = __($v['title']);
$v['url'] = preg_match("/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i", $v['url']) ? $v['url'] : url($v['url']); $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['menuclass'] = in_array($v['menutype'], ['dialog', 'ajax']) ? 'btn-' . $v['menutype'] : '';

View File

@ -231,15 +231,14 @@ trait Backend
$this->error(__("Invalid parameters")); $this->error(__("Invalid parameters"));
} }
$ids = $ids ?: $this->request->post('ids'); $ids = $ids ?: $this->request->post('ids');
if (empty($ids)) {
$this->error(__('Parameter %s can not be empty', '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);
} }
$this->model->where($pk, 'in', $ids); if ($ids) {
$this->model->where($pk, 'in', $ids);
}
$count = 0; $count = 0;
Db::startTrans(); Db::startTrans();
try { try {
@ -400,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'];
@ -460,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

@ -41,8 +41,8 @@ class AdminLog extends Model
/** /**
* 记录日志 * 记录日志
* @param string $title * @param string $title 日志标题
* @param string $content * @param string $content 日志内容
*/ */
public static function record($title = '', $content = '') public static function record($title = '', $content = '')
{ {
@ -50,6 +50,9 @@ class AdminLog extends Model
$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');
// 设置过滤函数
request()->filter('trim,strip_tags,htmlspecialchars');
$controllername = Loader::parseName(request()->controller()); $controllername = Loader::parseName(request()->controller());
$actionname = strtolower(request()->action()); $actionname = strtolower(request()->action());
$path = str_replace('.', '/', $controllername) . '/' . $actionname; $path = str_replace('.', '/', $controllername) . '/' . $actionname;
@ -60,12 +63,12 @@ class AdminLog extends Model
} }
} }
} }
$content = $content ? $content : self::$content; $content = $content ?: self::$content;
if (!$content) { if (!$content) {
$content = request()->param('', null, 'trim,strip_tags,htmlspecialchars'); $content = request()->param('') ?: file_get_contents("php://input");
$content = self::getPureContent($content); $content = self::getPureContent($content);
} }
$title = $title ? $title : self::$title; $title = $title ?: self::$title;
if (!$title) { if (!$title) {
$title = []; $title = [];
$breadcrumb = Auth::instance()->getBreadcrumb($path); $breadcrumb = Auth::instance()->getBreadcrumb($path);
@ -77,18 +80,18 @@ class AdminLog extends Model
self::create([ self::create([
'title' => $title, 'title' => $title,
'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $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 * @param $content
* @return false|string * @return array
*/ */
protected static function getPureContent($content) protected static function getPureContent($content)
{ {

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

@ -70,13 +70,13 @@
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}][]-{$key}"><input id="row[{$item.name}][]-{$key}" name="row[{$item.name}][]" type="checkbox" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name}][]-{$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} {/foreach}
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="row[{$item.name}]"></span>
{/case} {/case}
{case radio} {case radio}
{foreach name="item.content" item="vo"} {foreach name="item.content" item="vo"}
<label for="row[{$item.name}]-{$key}"><input id="row[{$item.name}]-{$key}" name="row[{$item.name}]" type="radio" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label> <label for="row[{$item.name}]-{$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} {/foreach}
<span class="msg-box n-right" for="c-{$item.name}"></span> <span class="msg-box n-right" for="row[{$item.name}]"></span>
{/case} {/case}
{case value="select" break="0"}{/case} {case value="select" break="0"}{/case}
{case value="selects"} {case value="selects"}
@ -89,20 +89,28 @@
{case value="image" break="0"}{/case} {case value="image" break="0"}{/case}
{case value="images"} {case value="images"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="35" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <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="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> <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> <ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul>
<span class="msg-box n-right" for="c-{$item.name}"></span>
</div> </div>
{/case} {/case}
{case value="file" break="0"}{/case} {case value="file" break="0"}{/case}
{case value="files"} {case value="files"}
<div class="form-inline"> <div class="form-inline">
<input id="c-{$item.name}" class="form-control" size="35" name="row[{$item.name}]" type="text" value="{$item.value|htmlentities}" data-tip="{$item.tip}"> <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="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><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> </div>
{/case} {/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} {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}]-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> <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>

View File

@ -62,6 +62,10 @@
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">
@ -152,60 +156,22 @@
</div> </div>
</form> </form>
</script> </script>
<script id="logintpl" type="text/html">
<div>
<form class="form-horizontal">
<fieldset>
<div class="alert alert-dismissable alert-danger">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{:__('Warning')}</strong><br/>{:__('Login tips')}
</div>
<div class="form-group">
<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>
</script>
<script id="userinfotpl" type="text/html">
<div>
<form class="form-horizontal form-userinfo">
<fieldset>
<div class="alert alert-dismissable alert-info-light">
<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-cube"></i> {:__('My addons')}</a></div>
</form>
</div>
</script>
<script id="uninstalltpl" type="text/html"> <script id="uninstalltpl" type="text/html">
<div class=""> <div class="">
<div class=""><%=#__("Are you sure you want to unstall %s?", addon['title'])%> <div class=""><%=#__("Are you sure you want to unstall %s?", addon['title'])%>
<p class="text-danger">{:__('Delete all the addon file and cannot be recovered!')} </p> <p class="text-danger">{:__('Delete all the addon file and cannot be recovered!')} </p>
{if config('app_debug')} {if config('app_debug')}
<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> <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>
{/if} {/if}
<p class="text-danger">{:__('Please backup important data manually before uninstall!')}</p> <p class="text-danger">{:__('Please backup important data manually before uninstall!')}</p>
</div> </div>
</div> </div>
</script> </script>
<script id="upgradetpl" type="text/html">
<div class="">
<div class=""><%=#__("Upgrade tips", addon['title'])%></div>
</div>
</script>
<script id="conflicttpl" type="text/html"> <script id="conflicttpl" type="text/html">
<div class="alert alert-dismissable alert-danger"> <div class="alert alert-dismissable alert-danger">
<button type="button" class="close" data-dismiss="alert">×</button> <button type="button" class="close" data-dismiss="alert">×</button>
@ -239,7 +205,7 @@
<% 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>
@ -247,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 if(typeof item.releaselist !="undefined" && item.releaselist.length>0){%> <% }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>
<% } %> <% } %>

View File

@ -39,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">

View File

@ -34,8 +34,8 @@
<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="{$row.icon}" id="icon-style"></i></span> <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}" /> <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>
@ -67,7 +67,7 @@
<div class="form-group"> <div class="form-group">
<label for="weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label> <label for="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 type="text" class="form-control" id="weigh" name="row[weigh]" value="{$row.weigh}" data-rule="required" /> <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">

View File

@ -52,7 +52,7 @@
<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="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="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>
@ -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">

View File

@ -22,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">
@ -40,7 +40,7 @@
<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> </div>
<div class="form-group"> <div class="form-group">
@ -52,7 +52,7 @@
<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">
@ -76,7 +76,7 @@
<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">

View File

@ -21,15 +21,6 @@
visibility: visible; visibility: visible;
} }
@media (max-width: 767px) {
.edit-form table tr th:nth-last-child(-n + 2), .edit-form table tr td:nth-last-child(-n + 2) {
display: none;
}
.edit-form table tr td .msg-box {
display: none;
}
}
</style> </style>
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
<div class="panel-heading"> <div class="panel-heading">

View File

@ -28,12 +28,12 @@
<div class="content-wrapper tab-content tab-addtabs"> <div class="content-wrapper tab-content tab-addtabs">
{if $fixedmenu} {if $fixedmenu}
<div role="tabpanel" class="tab-pane {:$referermenu?'':'active'}" id="con_{$fixedmenu.id}"> <div role="tabpanel" class="tab-pane {:$referermenu?'':'active'}" id="con_{$fixedmenu.id}">
<iframe src="{$fixedmenu.url}?addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe> <iframe src="{$fixedmenu.url}{:stripos($fixedmenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe>
</div> </div>
{/if} {/if}
{if $referermenu} {if $referermenu}
<div role="tabpanel" class="tab-pane active" id="con_{$referermenu.id}"> <div role="tabpanel" class="tab-pane active" id="con_{$referermenu.id}">
<iframe src="{$referermenu.url}?addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe> <iframe src="{$referermenu.url}{:stripos($referermenu.url, '?') !== false ? '&' : '?'}addtabs=1" width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling-x="no" scrolling-y="auto" allowtransparency="yes"></iframe>
</div> </div>
{/if} {/if}
</div> </div>

View File

@ -28,7 +28,7 @@
box-shadow: 0 0 30px rgba(0, 0, 0, 0.1); box-shadow: 0 0 30px rgba(0, 0, 0, 0.1);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
border: none; border: none;
overflow: hidden; /*overflow: hidden;*/
padding: 0; padding: 0;
} }
@ -55,6 +55,7 @@
.login-head { .login-head {
background: #899fe1; background: #899fe1;
border-radius: 3px 3px 0 0;
} }
.login-form { .login-form {
@ -122,12 +123,14 @@
</div> </div>
{/if} {/if}
<!--@CaptchaEnd--> <!--@CaptchaEnd-->
{if $keeyloginhours>0}
<div class="form-group checkbox"> <div class="form-group checkbox">
<label class="inline" for="keeplogin"> <label class="inline" for="keeplogin" data-toggle="tooltip" title="{:__('The duration of the session is %s hours', $keeyloginhours)}">
<input type="checkbox" name="keeplogin" id="keeplogin" value="1"/> <input type="checkbox" name="keeplogin" id="keeplogin" value="1"/>
{:__('Keep login')} {:__('Keep login')}
</label> </label>
</div> </div>
{/if}
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-success btn-lg btn-block" style="background:#708eea;">{:__('Sign in')}</button> <button type="submit" class="btn btn-success btn-lg btn-block" style="background:#708eea;">{:__('Sign in')}</button>
</div> </div>

View File

@ -1,6 +1,6 @@
<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()} {:token()}
<input type="hidden" name="row[rules]" value="{$row.rules}" /> <input type="hidden" name="row[rules]" value="{$row.rules|htmlentities}" />
<div class="form-group"> <div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">

View File

@ -33,7 +33,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">

View File

@ -14,6 +14,7 @@
<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> <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> </ul>
</div> </div>
<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-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('user/rule/edit')}" data-operate-edit="{:$auth->check('user/rule/edit')}"

View File

@ -1,8 +1,8 @@
<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()} {:token()}
<input type="hidden" name="row[id]" value="{$row.id}"> <input type="hidden" name="row[id]" value="{$row.id|htmlentities}">
<div class="form-group"> <div class="form-group">
<label for="c-group_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
{$groupList} {$groupList}
</div> </div>
@ -28,20 +28,20 @@
<div class="form-group"> <div class="form-group">
<label for="c-email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label> <label for="c-email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-email" data-rule="" class="form-control" name="row[email]" type="text" value="{$row.email|htmlentities}"> <input id="c-email" data-rule="email" class="form-control" name="row[email]" type="text" value="{$row.email|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label> <label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-mobile" data-rule="" class="form-control" name="row[mobile]" type="text" value="{$row.mobile|htmlentities}"> <input id="c-mobile" data-rule="mobile" class="form-control" name="row[mobile]" type="text" value="{$row.mobile|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-avatar" class="control-label col-xs-12 col-sm-2">{:__('Avatar')}:</label> <label for="c-avatar" class="control-label col-xs-12 col-sm-2">{:__('Avatar')}:</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-avatar" data-rule="" class="form-control" size="50" name="row[avatar]" type="text" value="{$row.avatar}"> <input id="c-avatar" data-rule="" class="form-control" size="50" name="row[avatar]" type="text" value="{$row.avatar|htmlentities}">
<div class="input-group-addon no-border no-padding"> <div class="input-group-addon no-border no-padding">
<span><button type="button" id="faupload-avatar" class="btn btn-danger faupload" data-input-id="c-avatar" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-avatar"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> <span><button type="button" id="faupload-avatar" class="btn btn-danger faupload" data-input-id="c-avatar" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-avatar"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-avatar" class="btn btn-primary fachoose" data-input-id="c-avatar" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span> <span><button type="button" id="fachoose-avatar" class="btn btn-primary fachoose" data-input-id="c-avatar" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
@ -54,11 +54,11 @@
<div class="form-group"> <div class="form-group">
<label for="c-level" class="control-label col-xs-12 col-sm-2">{:__('Level')}:</label> <label for="c-level" class="control-label col-xs-12 col-sm-2">{:__('Level')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-level" data-rule="required" class="form-control" name="row[level]" type="number" value="{$row.level}"> <input id="c-level" data-rule="required" class="form-control" name="row[level]" type="number" value="{$row.level|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-gender" class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[gender]', ['1'=>__('Male'), '0'=>__('Female')], $row['gender'])} {:build_radios('row[gender]', ['1'=>__('Male'), '0'=>__('Female')], $row['gender'])}
</div> </div>
@ -66,7 +66,7 @@
<div class="form-group"> <div class="form-group">
<label for="c-birthday" class="control-label col-xs-12 col-sm-2">{:__('Birthday')}:</label> <label for="c-birthday" class="control-label col-xs-12 col-sm-2">{:__('Birthday')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-birthday" data-rule="" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-use-current="true" name="row[birthday]" type="text" value="{$row.birthday}"> <input id="c-birthday" data-rule="" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-use-current="true" name="row[birthday]" type="text" value="{$row.birthday|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -78,25 +78,25 @@
<div class="form-group"> <div class="form-group">
<label for="c-money" class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label> <label for="c-money" class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-money" data-rule="required" class="form-control" name="row[money]" type="number" value="{$row.money}"> <input id="c-money" data-rule="required" class="form-control" name="row[money]" type="number" value="{$row.money|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-score" class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label> <label for="c-score" class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score}"> <input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-successions" class="control-label col-xs-12 col-sm-2">{:__('Successions')}:</label> <label for="c-successions" class="control-label col-xs-12 col-sm-2">{:__('Successions')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-successions" data-rule="required" class="form-control" name="row[successions]" type="number" value="{$row.successions}"> <input id="c-successions" data-rule="required" class="form-control" name="row[successions]" type="number" value="{$row.successions|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-maxsuccessions" class="control-label col-xs-12 col-sm-2">{:__('Maxsuccessions')}:</label> <label for="c-maxsuccessions" class="control-label col-xs-12 col-sm-2">{:__('Maxsuccessions')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-maxsuccessions" data-rule="required" class="form-control" name="row[maxsuccessions]" type="number" value="{$row.maxsuccessions}"> <input id="c-maxsuccessions" data-rule="required" class="form-control" name="row[maxsuccessions]" type="number" value="{$row.maxsuccessions|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -114,19 +114,19 @@
<div class="form-group"> <div class="form-group">
<label for="c-loginip" class="control-label col-xs-12 col-sm-2">{:__('Loginip')}:</label> <label for="c-loginip" class="control-label col-xs-12 col-sm-2">{:__('Loginip')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-loginip" data-rule="required" class="form-control" name="row[loginip]" type="text" value="{$row.loginip}"> <input id="c-loginip" data-rule="required" class="form-control" name="row[loginip]" type="text" value="{$row.loginip|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label> <label for="c-loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-loginfailure" data-rule="required" class="form-control" name="row[loginfailure]" type="number" value="{$row.loginfailure}"> <input id="c-loginfailure" data-rule="required" class="form-control" name="row[loginfailure]" type="number" value="{$row.loginfailure|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-joinip" class="control-label col-xs-12 col-sm-2">{:__('Joinip')}:</label> <label for="c-joinip" class="control-label col-xs-12 col-sm-2">{:__('Joinip')}:</label>
<div class="col-xs-12 col-sm-4"> <div class="col-xs-12 col-sm-4">
<input id="c-joinip" data-rule="required" class="form-control" name="row[joinip]" type="text" value="{$row.joinip}"> <input id="c-joinip" data-rule="required" class="form-control" name="row[joinip]" type="text" value="{$row.joinip|htmlentities}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -136,7 +136,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" 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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div> </div>

View File

@ -8,6 +8,7 @@ use app\common\library\Upload;
use app\common\model\Area; use app\common\model\Area;
use app\common\model\Version; use app\common\model\Version;
use fast\Random; use fast\Random;
use think\captcha\Captcha;
use think\Config; use think\Config;
use think\Hook; use think\Hook;
@ -16,15 +17,30 @@ use think\Hook;
*/ */
class Common extends Api class Common extends Api
{ {
protected $noNeedLogin = ['init']; protected $noNeedLogin = ['init', 'captcha'];
protected $noNeedRight = '*'; protected $noNeedRight = '*';
public function _initialize()
{
if (isset($_SERVER['HTTP_ORIGIN'])) {
header('Access-Control-Expose-Headers: __token__');//跨域让客户端获取到
}
//跨域检测
check_cors_request();
if (!isset($_COOKIE['PHPSESSID'])) {
Config::set('session.id', $this->request->server("HTTP_SID"));
}
parent::_initialize();
}
/** /**
* 加载初始化 * 加载初始化
* *
* @param string $version 版本号 * @ApiParams (name="version", type="string", required=true, description="版本号")
* @param string $lng 经度 * @ApiParams (name="lng", type="string", required=true, description="经度")
* @param string $lat 纬度 * @ApiParams (name="lat", type="string", required=true, description="纬度")
*/ */
public function init() public function init()
{ {
@ -64,7 +80,7 @@ class Common extends Api
/** /**
* 上传文件 * 上传文件
* @ApiMethod (POST) * @ApiMethod (POST)
* @param File $file 文件流 * @ApiParams (name="file", type="File", required=true, description="文件流")
*/ */
public function upload() public function upload()
{ {
@ -121,10 +137,30 @@ class Common extends Api
$attachment = $upload->upload(); $attachment = $upload->upload();
} catch (UploadException $e) { } catch (UploadException $e) {
$this->error($e->getMessage()); $this->error($e->getMessage());
} catch (\Exception $e) {
$this->error($e->getMessage());
} }
$this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); $this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
} }
} }
/**
* 验证码
* @ApiParams (name="id", type="string", required=true, description="要生成验证码的标识")
* @return \think\Response
*/
public function captcha($id = "")
{
\think\Config::set([
'captcha' => array_merge(config('captcha'), [
'fontSize' => 44,
'imageH' => 150,
'imageW' => 350,
])
]);
$captcha = new Captcha((array)Config::get('captcha'));
return $captcha->entry($id);
}
} }

View File

@ -24,8 +24,8 @@ class Ems extends Api
* 发送验证码 * 发送验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $event 事件名称 * @ApiParams (name="event", type="string", required=true, description="事件名称")
*/ */
public function send() public function send()
{ {
@ -33,10 +33,35 @@ class Ems extends Api
$event = $this->request->post("event"); $event = $this->request->post("event");
$event = $event ? $event : 'register'; $event = $event ? $event : 'register';
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->error(__('邮箱格式错误'));
}
if (!preg_match("/^[a-z0-9_\-]{3,30}\$/i", $event)) {
$this->error(__('事件名称错误'));
}
//发送前验证码
if (config('fastadmin.user_api_captcha')) {
if (!preg_match("/^[a-z0-9]{4,6}\$/i", $captcha)) {
$this->error(__('验证码格式错误'));
}
if (!\think\Validate::is($captcha, 'captcha')) {
$this->error("验证码不正确");
}
}
$last = Emslib::get($email, $event); $last = Emslib::get($email, $event);
if ($last && time() - $last['createtime'] < 60) { if ($last && time() - $last['createtime'] < 60) {
$this->error(__('发送频繁')); $this->error(__('发送频繁'));
} }
$ipSendTotal = \app\common\model\Ems::where(['ip' => $this->request->ip()])->whereTime('createtime', '-1 hours')->count();
if ($ipSendTotal >= 5) {
$this->error(__('发送频繁'));
}
if ($event) { if ($event) {
$userinfo = User::getByEmail($email); $userinfo = User::getByEmail($email);
if ($event == 'register' && $userinfo) { if ($event == 'register' && $userinfo) {
@ -62,9 +87,9 @@ class Ems extends Api
* 检测验证码 * 检测验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $event 事件名称 * @ApiParams (name="event", type="string", required=true, description="事件名称")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function check() public function check()
{ {
@ -73,6 +98,17 @@ class Ems extends Api
$event = $event ? $event : 'register'; $event = $event ? $event : 'register';
$captcha = $this->request->post("captcha"); $captcha = $this->request->post("captcha");
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->error(__('邮箱格式错误'));
}
if (!preg_match("/^[a-z0-9_\-]{3,30}\$/i", $event)) {
$this->error(__('事件名称错误'));
}
if (!preg_match("/^[a-z0-9]{4,6}\$/i", $captcha)) {
$this->error(__('验证码格式错误'));
}
if ($event) { if ($event) {
$userinfo = User::getByEmail($email); $userinfo = User::getByEmail($email);
if ($event == 'register' && $userinfo) { if ($event == 'register' && $userinfo) {

View File

@ -19,8 +19,8 @@ class Sms extends Api
* 发送验证码 * 发送验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $event 事件名称 * @ApiParams (name="event", type="string", required=true, description="事件名称")
*/ */
public function send() public function send()
{ {
@ -67,9 +67,9 @@ class Sms extends Api
* 检测验证码 * 检测验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $event 事件名称 * @ApiParams (name="event", type="string", required=true, description="事件名称")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function check() public function check()
{ {

View File

@ -39,8 +39,8 @@ class User extends Api
* 会员登录 * 会员登录
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $account 账号 * @ApiParams (name="account", type="string", required=true, description="账号")
* @param string $password 密码 * @ApiParams (name="password", type="string", required=true, description="密码")
*/ */
public function login() public function login()
{ {
@ -62,8 +62,8 @@ class User extends Api
* 手机验证码登录 * 手机验证码登录
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function mobilelogin() public function mobilelogin()
{ {
@ -101,11 +101,11 @@ class User extends Api
* 注册会员 * 注册会员
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $username 用户名 * @ApiParams (name="username", type="string", required=true, description="用户名")
* @param string $password 密码 * @ApiParams (name="password", type="string", required=true, description="密码")
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $code 验证码 * @ApiParams (name="code", type="string", required=true, description="验证码")
*/ */
public function register() public function register()
{ {
@ -153,10 +153,10 @@ class User extends Api
* 修改会员个人信息 * 修改会员个人信息
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $avatar 头像地址 * @ApiParams (name="avatar", type="string", required=true, description="头像地址")
* @param string $username 用户名 * @ApiParams (name="username", type="string", required=true, description="用户名")
* @param string $nickname 昵称 * @ApiParams (name="nickname", type="string", required=true, description="昵称")
* @param string $bio 个人简介 * @ApiParams (name="bio", type="string", required=true, description="个人简介")
*/ */
public function profile() public function profile()
{ {
@ -189,8 +189,8 @@ class User extends Api
* 修改邮箱 * 修改邮箱
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function changeemail() public function changeemail()
{ {
@ -224,8 +224,8 @@ class User extends Api
* 修改手机号 * 修改手机号
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function changemobile() public function changemobile()
{ {
@ -259,8 +259,8 @@ class User extends Api
* 第三方登录 * 第三方登录
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $platform 平台名称 * @ApiParams (name="platform", type="string", required=true, description="平台名称")
* @param string $code Code码 * @ApiParams (name="code", type="string", required=true, description="Code码")
*/ */
public function third() public function third()
{ {
@ -291,13 +291,13 @@ class User extends Api
* 重置密码 * 重置密码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $newpassword 新密码 * @ApiParams (name="newpassword", type="string", required=true, description="新密码")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/ */
public function resetpwd() public function resetpwd()
{ {
$type = $this->request->post("type"); $type = $this->request->post("type", "mobile");
$mobile = $this->request->post("mobile"); $mobile = $this->request->post("mobile");
$email = $this->request->post("email"); $email = $this->request->post("email");
$newpassword = $this->request->post("newpassword"); $newpassword = $this->request->post("newpassword");

View File

@ -23,8 +23,8 @@ class Validate extends Api
* 检测邮箱 * 检测邮箱
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $id 排除会员ID * @ApiParams (name="id", type="string", required=true, description="排除会员ID")
*/ */
public function check_email_available() public function check_email_available()
{ {
@ -41,8 +41,8 @@ class Validate extends Api
* 检测用户名 * 检测用户名
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $username 用户名 * @ApiParams (name="username", type="string", required=true, description="用户名")
* @param string $id 排除会员ID * @ApiParams (name="id", type="string", required=true, description="排除会员ID")
*/ */
public function check_username_available() public function check_username_available()
{ {
@ -59,8 +59,8 @@ class Validate extends Api
* 检测昵称 * 检测昵称
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $nickname 昵称 * @ApiParams (name="nickname", type="string", required=true, description="昵称")
* @param string $id 排除会员ID * @ApiParams (name="id", type="string", required=true, description="排除会员ID")
*/ */
public function check_nickname_available() public function check_nickname_available()
{ {
@ -77,8 +77,8 @@ class Validate extends Api
* 检测手机 * 检测手机
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $id 排除会员ID * @ApiParams (name="id", type="string", required=true, description="排除会员ID")
*/ */
public function check_mobile_available() public function check_mobile_available()
{ {
@ -95,7 +95,7 @@ class Validate extends Api
* 检测手机 * 检测手机
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
*/ */
public function check_mobile_exist() public function check_mobile_exist()
{ {
@ -111,7 +111,7 @@ class Validate extends Api
* 检测邮箱 * 检测邮箱
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
*/ */
public function check_email_exist() public function check_email_exist()
{ {
@ -127,9 +127,9 @@ class Validate extends Api
* 检测手机验证码 * 检测手机验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $mobile 手机号 * @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
* @param string $event 事件 * @ApiParams (name="event", type="string", required=true, description="事件")
*/ */
public function check_sms_correct() public function check_sms_correct()
{ {
@ -146,9 +146,9 @@ class Validate extends Api
* 检测邮箱验证码 * 检测邮箱验证码
* *
* @ApiMethod (POST) * @ApiMethod (POST)
* @param string $email 邮箱 * @ApiParams (name="email", type="string", required=true, description="邮箱")
* @param string $captcha 验证码 * @ApiParams (name="captcha", type="string", required=true, description="验证码")
* @param string $event 事件 * @ApiParams (name="event", type="string", required=true, description="事件")
*/ */
public function check_ems_correct() public function check_ems_correct()
{ {

View File

@ -86,7 +86,7 @@ return [
'You can only upload a maximum of %s files' => '你最多允许上传 %s 个文件', 'You can only upload a maximum of %s files' => '你最多允许上传 %s 个文件',
'You can\'t upload files of this type' => '不允许上传的文件类型', 'You can\'t upload files of this type' => '不允许上传的文件类型',
'Server responded with %s code' => '服务端响应(Code:%s)', 'Server responded with %s code' => '服务端响应(Code:%s)',
'File is too big (%sMiB), Max filesize: %sMiB' => '当前上传(%sM),最大允许上传文件大小:%sM', 'File is too big (%sMiB), Max filesize: %sMiB.' => '当前上传(%sM),最大允许上传文件大小:%sM',
'Redirect now' => '立即跳转', 'Redirect now' => '立即跳转',
'Operation completed' => '操作成功!', 'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!', 'Operation failed' => '操作失败!',

View File

@ -2,7 +2,6 @@
// 公共助手函数 // 公共助手函数
use Symfony\Component\VarExporter\VarExporter;
use think\exception\HttpResponseException; use think\exception\HttpResponseException;
use think\Response; use think\Response;
@ -11,7 +10,7 @@ if (!function_exists('__')) {
/** /**
* 获取语言变量值 * 获取语言变量值
* @param string $name 语言变量名 * @param string $name 语言变量名
* @param array $vars 动态变量值 * @param string | array $vars 动态变量值
* @param string $lang 语言 * @param string $lang 语言
* @return mixed * @return mixed
*/ */
@ -41,7 +40,7 @@ if (!function_exists('format_bytes')) {
function format_bytes($size, $delimiter = '', $precision = 2) function format_bytes($size, $delimiter = '', $precision = 2)
{ {
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
for ($i = 0; $size >= 1024 && $i < 6; $i++) { for ($i = 0; $size >= 1024 && $i < 5; $i++) {
$size /= 1024; $size /= 1024;
} }
return round($size, $precision) . $delimiter . $units[$i]; return round($size, $precision) . $delimiter . $units[$i];
@ -89,7 +88,9 @@ if (!function_exists('cdnurl')) {
{ {
$regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i"; $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
$cdnurl = \think\Config::get('upload.cdnurl'); $cdnurl = \think\Config::get('upload.cdnurl');
$url = preg_match($regex, $url) || ($cdnurl && stripos($url, $cdnurl) === 0) ? $url : $cdnurl . $url; if (is_bool($domain) || stripos($cdnurl, '/') === 0) {
$url = preg_match($regex, $url) || ($cdnurl && stripos($url, $cdnurl) === 0) ? $url : $cdnurl . $url;
}
if ($domain && !preg_match($regex, $url)) { if ($domain && !preg_match($regex, $url)) {
$domain = is_bool($domain) ? request()->domain() : $domain; $domain = is_bool($domain) ? request()->domain() : $domain;
$url = $domain . $url; $url = $domain . $url;
@ -216,7 +217,7 @@ if (!function_exists('addtion')) {
} else { } else {
foreach ($fields as $k => $v) { foreach ($fields as $k => $v) {
if (is_array($v)) { if (is_array($v)) {
$v['field'] = isset($v['field']) ? $v['field'] : $k; $v['field'] = $v['field'] ?? $k;
} else { } else {
$v = ['field' => $v]; $v = ['field' => $v];
} }
@ -225,12 +226,12 @@ if (!function_exists('addtion')) {
} }
foreach ($fieldsArr as $k => &$v) { foreach ($fieldsArr as $k => &$v) {
$v = is_array($v) ? $v : ['field' => $v]; $v = is_array($v) ? $v : ['field' => $v];
$v['display'] = isset($v['display']) ? $v['display'] : str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']); $v['display'] = $v['display'] ?? str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
$v['primary'] = isset($v['primary']) ? $v['primary'] : ''; $v['primary'] = $v['primary'] ?? '';
$v['column'] = isset($v['column']) ? $v['column'] : 'name'; $v['column'] = $v['column'] ?? 'name';
$v['model'] = isset($v['model']) ? $v['model'] : ''; $v['model'] = $v['model'] ?? '';
$v['table'] = isset($v['table']) ? $v['table'] : ''; $v['table'] = $v['table'] ?? '';
$v['name'] = isset($v['name']) ? $v['name'] : str_replace(['_ids', '_id'], '', $v['field']); $v['name'] = $v['name'] ?? str_replace(['_ids', '_id'], '', $v['field']);
} }
unset($v); unset($v);
$ids = []; $ids = [];
@ -247,9 +248,10 @@ if (!function_exists('addtion')) {
if ($v['model']) { if ($v['model']) {
$model = new $v['model']; $model = new $v['model'];
} else { } else {
$model = $v['name'] ? \think\Db::name($v['name']) : \think\Db::table($v['table']); // 优先判断使用table的配置
$model = $v['table'] ? \think\Db::table($v['table']) : \think\Db::name($v['name']);
} }
$primary = $v['primary'] ? $v['primary'] : $model->getPk(); $primary = $v['primary'] ?: $model->getPk();
$result[$v['field']] = isset($ids[$v['field']]) ? $model->where($primary, 'in', $ids[$v['field']])->column($v['column'], $primary) : []; $result[$v['field']] = isset($ids[$v['field']]) ? $model->where($primary, 'in', $ids[$v['field']])->column($v['column'], $primary) : [];
} }
@ -278,60 +280,6 @@ if (!function_exists('var_export_short')) {
function var_export_short($data, $return = true) function var_export_short($data, $return = true)
{ {
return var_export($data, $return); return var_export($data, $return);
$replaced = [];
$count = 0;
//判断是否是对象
if (is_resource($data) || is_object($data)) {
return var_export($data, $return);
}
//判断是否有特殊的键名
$specialKey = false;
array_walk_recursive($data, function (&$value, &$key) use (&$specialKey) {
if (is_string($key) && (stripos($key, "\n") !== false || stripos($key, "array (") !== false)) {
$specialKey = true;
}
});
if ($specialKey) {
return var_export($data, $return);
}
array_walk_recursive($data, function (&$value, &$key) use (&$replaced, &$count, &$stringcheck) {
if (is_object($value) || is_resource($value)) {
$replaced[$count] = var_export($value, true);
$value = "##<{$count}>##";
} else {
if (is_string($value) && (stripos($value, "\n") !== false || stripos($value, "array (") !== false)) {
$index = array_search($value, $replaced);
if ($index === false) {
$replaced[$count] = var_export($value, true);
$value = "##<{$count}>##";
} else {
$value = "##<{$index}>##";
}
}
}
$count++;
});
$dump = var_export($data, true);
$dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
$dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
$dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
$dump = preg_replace('#\)$#', "]", $dump); //End
if ($replaced) {
$dump = preg_replace_callback("/'##<(\d+)>##'/", function ($matches) use ($replaced) {
return isset($replaced[$matches[1]]) ? $replaced[$matches[1]] : "''";
}, $dump);
}
if ($return === true) {
return $dump;
} else {
echo $dump;
}
} }
} }
@ -427,7 +375,7 @@ if (!function_exists('check_cors_request')) {
*/ */
function check_cors_request() function check_cors_request()
{ {
if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN']) { if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] && config('fastadmin.cors_request_domain')) {
$info = parse_url($_SERVER['HTTP_ORIGIN']); $info = parse_url($_SERVER['HTTP_ORIGIN']);
$domainArr = explode(',', config('fastadmin.cors_request_domain')); $domainArr = explode(',', config('fastadmin.cors_request_domain'));
$domainArr[] = request()->host(true); $domainArr[] = request()->host(true);
@ -465,6 +413,19 @@ if (!function_exists('xss_clean')) {
} }
} }
if (!function_exists('url_clean')) {
/**
* 清理URL
*/
function url_clean($url)
{
if (!check_url_allowed($url)) {
return '';
}
return xss_clean($url);
}
}
if (!function_exists('check_ip_allowed')) { if (!function_exists('check_ip_allowed')) {
/** /**
* 检测IP是否允许 * 检测IP是否允许
@ -483,6 +444,40 @@ if (!function_exists('check_ip_allowed')) {
} }
} }
if (!function_exists('check_url_allowed')) {
/**
* 检测URL是否允许
* @param string $url URL
* @return bool
*/
function check_url_allowed($url = '')
{
//允许的主机列表
$allowedHostArr = [
strtolower(request()->host())
];
if (empty($url)) {
return true;
}
//如果是站内相对链接则允许
if (preg_match("/^[\/a-z][a-z0-9][a-z0-9\.\/]+((\?|#).*)?\$/i", $url) && substr($url, 0, 2) !== '//') {
return true;
}
//如果是站外链接则需要判断HOST是否允许
if (preg_match("/((http[s]?:\/\/)+((?>[a-z\-0-9]{2,}\.)+[a-z]{2,8}|((?>([0-9]{1,3}\.)){3}[0-9]{1,3}))(:[0-9]{1,5})?)(?:\s|\/)/i", $url)) {
$chkHost = parse_url(strtolower($url), PHP_URL_HOST);
if ($chkHost && in_array($chkHost, $allowedHostArr)) {
return true;
}
}
return false;
}
}
if (!function_exists('build_suffix_image')) { if (!function_exists('build_suffix_image')) {
/** /**
* 生成文件后缀图片 * 生成文件后缀图片

View File

@ -63,7 +63,7 @@ class Common
} }
// 切换多语言 // 切换多语言
if (Config::get('lang_switch_on')) { if (Config::get('lang_switch_on')) {
$lang = $request->get('lang'); $lang = $request->get('lang', '');
if (preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang)) { if (preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang)) {
\think\Cookie::set('think_var', $lang); \think\Cookie::set('think_var', $lang);
} }

View File

@ -204,8 +204,8 @@ class Api
'time' => Request::instance()->server('REQUEST_TIME'), 'time' => Request::instance()->server('REQUEST_TIME'),
'data' => $data, 'data' => $data,
]; ];
// 如果未设置类型则自动判断 // 如果未设置类型则使用默认类型判断
$type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType); $type = $type ? : $this->responseType;
if (isset($header['statuscode'])) { if (isset($header['statuscode'])) {
$code = $header['statuscode']; $code = $header['statuscode'];

View File

@ -123,10 +123,10 @@ class Backend extends Controller
$path = str_replace('.', '/', $controllername) . '/' . $actionname; $path = str_replace('.', '/', $controllername) . '/' . $actionname;
// 定义是否Addtabs请求 // 定义是否Addtabs请求
!defined('IS_ADDTABS') && define('IS_ADDTABS', input("addtabs") ? true : false); !defined('IS_ADDTABS') && define('IS_ADDTABS', (bool)input("addtabs"));
// 定义是否Dialog请求 // 定义是否Dialog请求
!defined('IS_DIALOG') && define('IS_DIALOG', input("dialog") ? true : false); !defined('IS_DIALOG') && define('IS_DIALOG', (bool)input("dialog"));
// 定义是否AJAX请求 // 定义是否AJAX请求
!defined('IS_AJAX') && define('IS_AJAX', $this->request->isAjax()); !defined('IS_AJAX') && define('IS_AJAX', $this->request->isAjax());
@ -268,12 +268,13 @@ class Backend extends Controller
$op = $this->request->get("op", '', 'trim'); $op = $this->request->get("op", '', 'trim');
$sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id'); $sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
$order = $this->request->get("order", "DESC"); $order = $this->request->get("order", "DESC");
$offset = $this->request->get("offset/d", 0); $offset = max(0, $this->request->get("offset/d", 0));
$limit = $this->request->get("limit/d", 999999); $limit = max(0, $this->request->get("limit/d", 0));
$limit = $limit ?: 999999;
//新增自动计算页码 //新增自动计算页码
$page = $limit ? intval($offset / $limit) + 1 : 1; $page = $limit ? intval($offset / $limit) + 1 : 1;
if ($this->request->has("page")) { if ($this->request->has("page")) {
$page = $this->request->get("page/d", 1); $page = max(0, $this->request->get("page/d", 1));
} }
$this->request->get([config('paginate.var_page') => $page]); $this->request->get([config('paginate.var_page') => $page]);
$filter = (array)json_decode($filter, true); $filter = (array)json_decode($filter, true);
@ -284,7 +285,7 @@ class Backend extends Controller
$bind = []; $bind = [];
$name = ''; $name = '';
$aliasName = ''; $aliasName = '';
if (!empty($this->model) && $this->relationSearch) { if (!empty($this->model) && $relationSearch) {
$name = $this->model->getTable(); $name = $this->model->getTable();
$alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model)))); $alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
$aliasName = $alias[$name] . '.'; $aliasName = $alias[$name] . '.';
@ -312,12 +313,12 @@ class Backend extends Controller
if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) { if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) {
continue; continue;
} }
$sym = isset($op[$k]) ? $op[$k] : '='; $sym = $op[$k] ?? '=';
if (stripos($k, ".") === false) { if (stripos($k, ".") === false) {
$k = $aliasName . $k; $k = $aliasName . $k;
} }
$v = !is_array($v) ? trim($v) : $v; $v = !is_array($v) ? trim($v) : $v;
$sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym); $sym = strtoupper($op[$k] ?? $sym);
//null和空字符串特殊处理 //null和空字符串特殊处理
if (!is_array($v)) { if (!is_array($v)) {
if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) { if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) {
@ -367,8 +368,8 @@ class Backend extends Controller
case 'NOT BETWEEN': case 'NOT BETWEEN':
$arr = array_slice(explode(',', $v), 0, 2); $arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr, function ($v) { if (stripos($v, ',') === false || !array_filter($arr, function ($v) {
return $v != '' && $v !== false && $v !== null; return $v != '' && $v !== false && $v !== null;
})) { })) {
continue 2; continue 2;
} }
//当出现一边为空时改变操作符 //当出现一边为空时改变操作符
@ -397,7 +398,8 @@ class Backend extends Controller
$arr = $arr[0]; $arr = $arr[0];
} }
$tableArr = explode('.', $k); $tableArr = explode('.', $k);
if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias) && !empty($this->model)) { if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias)
&& !empty($this->model) && $this->relationSearch) {
//修复关联模型下时间无法搜索的BUG //修复关联模型下时间无法搜索的BUG
$relation = Loader::parseName($tableArr[0], 1, false); $relation = Loader::parseName($tableArr[0], 1, false);
$alias[$this->model->$relation()->getTable()] = $tableArr[0]; $alias[$this->model->$relation()->getTable()] = $tableArr[0];
@ -568,8 +570,8 @@ class Backend extends Controller
unset($item['password'], $item['salt']); unset($item['password'], $item['salt']);
if ($this->selectpageFields == '*') { if ($this->selectpageFields == '*') {
$result = [ $result = [
$primarykey => isset($item[$primarykey]) ? $item[$primarykey] : '', $primarykey => $item[$primarykey] ?? '',
$field => isset($item[$field]) ? $item[$field] : '', $field => $item[$field] ?? '',
]; ];
} else { } else {
$result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields)); $result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields));

View File

@ -164,7 +164,7 @@ class Auth
'avatar' => '', 'avatar' => '',
]; ];
$params = array_merge($data, [ $params = array_merge($data, [
'nickname' => preg_match("/^1[3-9]{1}\d{9}$/",$username) ? substr_replace($username,'****',3,4) : $username, 'nickname' => preg_match("/^1[3-9]{1}\d{9}$/", $username) ? substr_replace($username, '****', 3, 4) : $username,
'salt' => Random::alnum(), 'salt' => Random::alnum(),
'jointime' => $time, 'jointime' => $time,
'joinip' => $ip, 'joinip' => $ip,
@ -221,7 +221,13 @@ class Auth
$this->setError('Account is locked'); $this->setError('Account is locked');
return false; return false;
} }
if ($user->loginfailure >= 10 && time() - $user->loginfailuretime < 86400) {
$this->setError('Please try again after 1 day');
}
if ($user->password != $this->getEncryptPassword($password, $user->salt)) { if ($user->password != $this->getEncryptPassword($password, $user->salt)) {
$user->save(['loginfailure' => $user->loginfailure + 1, 'loginfailuretime' => time()]);
$this->setError('Password is incorrect'); $this->setError('Password is incorrect');
return false; return false;
} }
@ -356,7 +362,7 @@ class Auth
} }
$url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path); $url = ($module ? $module : request()->module()) . '/' . (is_null($path) ? $this->getRequestUri() : $path);
$url = strtolower(str_replace('.', '/', $url)); $url = strtolower(str_replace('.', '/', $url));
return in_array($url, $rules) ? true : false; return in_array($url, $rules);
} }
/** /**
@ -394,7 +400,7 @@ class Auth
/** /**
* 获取会员组别规则列表 * 获取会员组别规则列表
* @return array * @return array|bool|\PDOStatement|string|\think\Collection
*/ */
public function getRuleList() public function getRuleList()
{ {
@ -547,7 +553,7 @@ class Auth
} }
} }
foreach ($datalist as $k => &$v) { foreach ($datalist as $k => &$v) {
$v[$renderkey] = isset($list[$v[$fieldkey]]) ? $list[$v[$fieldkey]] : null; $v[$renderkey] = $list[$v[$fieldkey]] ?? null;
} }
unset($v); unset($v);
return $datalist; return $datalist;

View File

@ -60,7 +60,7 @@ class Email
} }
$this->options = array_merge($this->options, $options); $this->options = array_merge($this->options, $options);
$secureArr = [0 => '', 1 => 'tls', 2 => 'ssl']; $secureArr = [0 => '', 1 => 'tls', 2 => 'ssl'];
$secure = isset($secureArr[$this->options['mail_verify_type']]) ? $secureArr[$this->options['mail_verify_type']] : ''; $secure = $secureArr[$this->options['mail_verify_type']] ?? '';
$logger = isset($this->options['debug']) && $this->options['debug'] ? new Log : null; $logger = isset($this->options['debug']) && $this->options['debug'] ? new Log : null;
$this->mail = new Mailer($logger); $this->mail = new Mailer($logger);
@ -217,8 +217,8 @@ class Email
$this->setError($e->getCode() . $e->getMessage()); $this->setError($e->getCode() . $e->getMessage());
} catch (CodeException $e) { } catch (CodeException $e) {
preg_match_all("/Expected: (\d+)\, Got: (\d+)( \| (.*))?\$/i", $e->getMessage(), $matches); preg_match_all("/Expected: (\d+)\, Got: (\d+)( \| (.*))?\$/i", $e->getMessage(), $matches);
$code = isset($matches[2][3]) ? $matches[2][3] : 0; $code = $matches[2][0] ?? 0;
$message = isset($matches[2][0]) ? $matches[4][0] : $e->getMessage(); $message = isset($matches[2][0]) && isset($matches[4][0]) ? $matches[4][0] : $e->getMessage();
$message = mb_convert_encoding($message, 'UTF-8', 'GBK,GB2312,BIG5'); $message = mb_convert_encoding($message, 'UTF-8', 'GBK,GB2312,BIG5');
$this->setError($message); $this->setError($message);
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@ -28,16 +28,15 @@ class Ems
* *
* @param int $email 邮箱 * @param int $email 邮箱
* @param string $event 事件 * @param string $event 事件
* @return Ems * @return Ems|null
*/ */
public static function get($email, $event = 'default') public static function get($email, $event = 'default')
{ {
$ems = \app\common\model\Ems:: $ems = \app\common\model\Ems::where(['email' => $email, 'event' => $event])
where(['email' => $email, 'event' => $event])
->order('id', 'DESC') ->order('id', 'DESC')
->find(); ->find();
Hook::listen('ems_get', $ems, null, true); Hook::listen('ems_get', $ems, null, true);
return $ems ? $ems : null; return $ems ?: null;
} }
/** /**
@ -103,7 +102,7 @@ class Ems
}); });
} }
$result = Hook::listen('ems_notice', $params, null, true); $result = Hook::listen('ems_notice', $params, null, true);
return $result ? true : false; return (bool)$result;
} }
/** /**
@ -150,8 +149,7 @@ class Ems
*/ */
public static function flush($email, $event = 'default') public static function flush($email, $event = 'default')
{ {
\app\common\model\Ems:: \app\common\model\Ems::where(['email' => $email, 'event' => $event])
where(['email' => $email, 'event' => $event])
->delete(); ->delete();
Hook::listen('ems_flush'); Hook::listen('ems_flush');
return true; return true;

View File

@ -14,9 +14,9 @@ class Log extends AbstractLogger
/** /**
* Logs with an arbitrary level. * Logs with an arbitrary level.
* *
* @param mixed $level * @param mixed $level
* @param string $message * @param string $message
* @param mixed[] $context * @param array $context
* *
* @return void * @return void
* *

View File

@ -100,7 +100,7 @@ class Menu
if ($ids) { if ($ids) {
//旧版本的菜单需要做删除处理 //旧版本的菜单需要做删除处理
$config = Service::config($name); $config = Service::config($name);
$menus = isset($config['menus']) ? $config['menus'] : []; $menus = $config['menus'] ?? [];
$where = ['id' => ['in', $ids]]; $where = ['id' => ['in', $ids]];
if ($menus) { if ($menus) {
//必须是旧版本中的菜单,可排除用户自主创建的菜单 //必须是旧版本中的菜单,可排除用户自主创建的菜单
@ -182,14 +182,14 @@ class Menu
} else { } else {
$pid = $parent; $pid = $parent;
} }
$allow = array_flip(['file', 'name', 'title', 'url', 'icon', 'condition', 'remark', 'ismenu', 'menutype', 'extend', 'weigh']); $allow = array_flip(['file', 'name', 'title', 'url', 'icon', 'condition', 'remark', 'ismenu', 'menutype', 'extend', 'weigh', 'status']);
foreach ($newMenu as $k => $v) { foreach ($newMenu as $k => $v) {
$hasChild = isset($v['sublist']) && $v['sublist'] ? true : false; $hasChild = isset($v['sublist']) && $v['sublist'];
$data = array_intersect_key($v, $allow); $data = array_intersect_key($v, $allow);
$data['ismenu'] = isset($data['ismenu']) ? $data['ismenu'] : ($hasChild ? 1 : 0); $data['ismenu'] = $data['ismenu'] ?? ($hasChild ? 1 : 0);
$data['icon'] = isset($data['icon']) ? $data['icon'] : ($hasChild ? 'fa fa-list' : 'fa fa-circle-o'); $data['icon'] = $data['icon'] ?? ($hasChild ? 'fa fa-list' : 'fa fa-circle-o');
$data['pid'] = $pid; $data['pid'] = $pid;
$data['status'] = 'normal'; $data['status'] = $data['status'] ?? 'normal';
if (!isset($oldMenu[$data['name']])) { if (!isset($oldMenu[$data['name']])) {
$menu = AuthRule::create($data); $menu = AuthRule::create($data);
} else { } else {

View File

@ -16,7 +16,6 @@ use Exception;
*/ */
class Security class Security
{ {
protected static $instance = null; protected static $instance = null;
/** /**
@ -420,7 +419,7 @@ class Security
*/ */
public function get_random_bytes($length) public function get_random_bytes($length)
{ {
if (empty($length) OR !ctype_digit((string)$length)) { if (empty($length) or !ctype_digit((string)$length)) {
return false; return false;
} }
@ -485,8 +484,8 @@ class Security
static $_entities; static $_entities;
isset($charset) OR $charset = $this->charset; isset($charset) or $charset = $this->charset;
isset($_entities) OR $_entities = array_map('strtolower', get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML5, $charset)); isset($_entities) or $_entities = array_map('strtolower', get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML5, $charset));
do { do {
$str_compare = $str; $str_compare = $str;
@ -698,7 +697,7 @@ class Security
// Is it indeed an "evil" attribute? // Is it indeed an "evil" attribute?
preg_match($is_evil_pattern, $attribute['name'][0]) preg_match($is_evil_pattern, $attribute['name'][0])
// Or does it have an equals sign, but no value and not quoted? Strip that too! // Or does it have an equals sign, but no value and not quoted? Strip that too!
OR (trim($attribute['value'][0]) === '') or (trim($attribute['value'][0]) === '')
) { ) {
$attributes[] = 'xss=removed'; $attributes[] = 'xss=removed';
} else { } else {
@ -870,5 +869,4 @@ class Security
return $str; return $str;
} }
} }

View File

@ -32,12 +32,11 @@ class Sms
*/ */
public static function get($mobile, $event = 'default') public static function get($mobile, $event = 'default')
{ {
$sms = \app\common\model\Sms:: $sms = \app\common\model\Sms::where(['mobile' => $mobile, 'event' => $event])
where(['mobile' => $mobile, 'event' => $event])
->order('id', 'DESC') ->order('id', 'DESC')
->find(); ->find();
Hook::listen('sms_get', $sms, null, true); Hook::listen('sms_get', $sms, null, true);
return $sms ? $sms : null; return $sms ?: null;
} }
/** /**
@ -78,7 +77,7 @@ class Sms
'template' => $template 'template' => $template
]; ];
$result = Hook::listen('sms_notice', $params, null, true); $result = Hook::listen('sms_notice', $params, null, true);
return $result ? true : false; return (bool)$result;
} }
/** /**
@ -125,8 +124,7 @@ class Sms
*/ */
public static function flush($mobile, $event = 'default') public static function flush($mobile, $event = 'default')
{ {
\app\common\model\Sms:: \app\common\model\Sms::where(['mobile' => $mobile, 'event' => $event])
where(['mobile' => $mobile, 'event' => $event])
->delete(); ->delete();
Hook::listen('sms_flush'); Hook::listen('sms_flush');
return true; return true;

View File

@ -150,7 +150,7 @@ class Token
/** /**
* 清除Token * 清除Token
* @access public * @access public
* @param int user_id 会员ID * @param int $user_id 会员ID
* @return boolean * @return boolean
*/ */
public static function clear($user_id = null) public static function clear($user_id = null)

View File

@ -15,7 +15,6 @@ use think\Hook;
*/ */
class Upload class Upload
{ {
protected $merging = false; protected $merging = false;
protected $chunkDir = null; protected $chunkDir = null;
@ -130,8 +129,8 @@ class Upload
if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) {
throw new UploadException(__('Uploaded file is not a valid image')); throw new UploadException(__('Uploaded file is not a valid image'));
} }
$this->fileInfo['imagewidth'] = isset($imgInfo[0]) ? $imgInfo[0] : 0; $this->fileInfo['imagewidth'] = $imgInfo[0] ?? 0;
$this->fileInfo['imageheight'] = isset($imgInfo[1]) ? $imgInfo[1] : 0; $this->fileInfo['imageheight'] = $imgInfo[1] ?? 0;
return true; return true;
} else { } else {
return !$force; return !$force;
@ -148,11 +147,13 @@ class Upload
$size = $matches ? $matches[1] : $this->config['maxsize']; $size = $matches ? $matches[1] : $this->config['maxsize'];
$type = $matches ? strtolower($matches[2]) : 'b'; $type = $matches ? strtolower($matches[2]) : 'b';
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int)($size * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0)); $size = (int)($size * pow(1024, $typeDict[$type] ?? 0));
if ($this->fileInfo['size'] > $size) { if ($this->fileInfo['size'] > $size) {
throw new UploadException(__('File is too big (%sMiB). Max filesize: %sMiB.', throw new UploadException(__(
'File is too big (%sMiB), Max filesize: %sMiB.',
round($this->fileInfo['size'] / pow(1024, 2), 2), round($this->fileInfo['size'] / pow(1024, 2), 2),
round($size / pow(1024, 2), 2))); round($size / pow(1024, 2), 2)
));
} }
} }
@ -167,35 +168,41 @@ class Upload
/** /**
* 获取存储的文件名 * 获取存储的文件名
* @param string $savekey * @param string $savekey 保存路径
* @param string $filename * @param string $filename 文件名
* @param string $md5 * @param string $md5 文件MD5
* @param string $category 分类
* @return mixed|null * @return mixed|null
*/ */
public function getSavekey($savekey = null, $filename = null, $md5 = null) public function getSavekey($savekey = null, $filename = null, $md5 = null, $category = null)
{ {
if ($filename) { if ($filename) {
$suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
} else { } else {
$suffix = $this->fileInfo['suffix']; $suffix = $this->fileInfo['suffix'] ?? '';
} }
$filename = $filename ? $filename : ($suffix ? substr($this->fileInfo['name'], 0, strripos($this->fileInfo['name'], '.')) : $this->fileInfo['name']); $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
$filename = $filename ? $filename : ($this->fileInfo['name'] ?? 'unknown');
$filename = xss_clean(strip_tags(htmlspecialchars($filename))); $filename = xss_clean(strip_tags(htmlspecialchars($filename)));
$md5 = $md5 ? $md5 : md5_file($this->fileInfo['tmp_name']); $fileprefix = substr($filename, 0, strripos($filename, '.'));
$md5 = $md5 ? $md5 : (isset($this->fileInfo['tmp_name']) ? md5_file($this->fileInfo['tmp_name']) : '');
$category = $category ? $category : request()->post('category');
$category = $category ? xss_clean($category) : 'all';
$replaceArr = [ $replaceArr = [
'{year}' => date("Y"), '{year}' => date("Y"),
'{mon}' => date("m"), '{mon}' => date("m"),
'{day}' => date("d"), '{day}' => date("d"),
'{hour}' => date("H"), '{hour}' => date("H"),
'{min}' => date("i"), '{min}' => date("i"),
'{sec}' => date("s"), '{sec}' => date("s"),
'{random}' => Random::alnum(16), '{random}' => Random::alnum(16),
'{random32}' => Random::alnum(32), '{random32}' => Random::alnum(32),
'{filename}' => substr($filename, 0, 100), '{category}' => $category ? $category : '',
'{suffix}' => $suffix, '{filename}' => substr($filename, 0, 100),
'{.suffix}' => $suffix ? '.' . $suffix : '', '{fileprefix}' => substr($fileprefix, 0, 100),
'{filemd5}' => $md5, '{suffix}' => $suffix,
'{.suffix}' => $suffix ? '.' . $suffix : '',
'{filemd5}' => $md5,
]; ];
$savekey = $savekey ? $savekey : $this->config['savekey']; $savekey = $savekey ? $savekey : $this->config['savekey'];
$savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey); $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
@ -298,7 +305,7 @@ class Upload
$attachment = $this->upload(); $attachment = $this->upload();
} catch (\Exception $e) { } catch (\Exception $e) {
@unlink($destFile); @unlink($uploadPath);
throw new UploadException($e->getMessage()); throw new UploadException($e->getMessage());
} }
return $attachment; return $attachment;
@ -310,7 +317,6 @@ class Upload
*/ */
public function chunk($chunkid, $chunkindex, $chunkcount, $chunkfilesize = null, $chunkfilename = null, $direct = false) public function chunk($chunkid, $chunkindex, $chunkcount, $chunkfilesize = null, $chunkfilename = null, $direct = false)
{ {
if ($this->fileInfo['type'] != 'application/octet-stream') { if ($this->fileInfo['type'] != 'application/octet-stream') {
throw new UploadException(__('Uploaded file format is limited')); throw new UploadException(__('Uploaded file format is limited'));
} }

View File

@ -76,6 +76,7 @@ abstract class Driver
protected function getEncryptedToken($token) protected function getEncryptedToken($token)
{ {
$config = \think\Config::get('token'); $config = \think\Config::get('token');
$token = $token ?? ''; // 为兼容 php8
return hash_hmac($config['hashalgo'], $token, $config['key']); return hash_hmac($config['hashalgo'], $token, $config['key']);
} }

View File

@ -60,6 +60,7 @@ class Redis extends Driver
protected function getEncryptedToken($token) protected function getEncryptedToken($token)
{ {
$config = \think\Config::get('token'); $config = \think\Config::get('token');
$token = $token ?? ''; // 为兼容 php8
return $this->options['tokenprefix'] . hash_hmac($config['hashalgo'], $token, $config['key']); return $this->options['tokenprefix'] . hash_hmac($config['hashalgo'], $token, $config['key']);
} }

View File

@ -22,8 +22,8 @@ class Area extends Model
{ {
$namearr = [1 => 'geo:province', 2 => 'geo:city', 3 => 'geo:district']; $namearr = [1 => 'geo:province', 2 => 'geo:city', 3 => 'geo:district'];
$rangearr = [1 => 15000, 2 => 1000, 3 => 200]; $rangearr = [1 => 15000, 2 => 1000, 3 => 200];
$geoname = isset($namearr[$level]) ? $namearr[$level] : $namearr[3]; $geoname = $namearr[$level] ?? $namearr[3];
$georange = isset($rangearr[$level]) ? $rangearr[$level] : $rangearr[3]; $georange = $rangearr[$level] ?? $rangearr[3];
// 读取范围内的ID // 读取范围内的ID
$redis = Cache::store('redis')->handler(); $redis = Cache::store('redis')->handler();
$georadiuslist = []; $georadiuslist = [];

View File

@ -24,7 +24,9 @@ class Category extends Model
protected static function init() protected static function init()
{ {
self::afterInsert(function ($row) { self::afterInsert(function ($row) {
$row->save(['weigh' => $row['id']]); if (!$row['weigh']) {
$row->save(['weigh' => $row['id']]);
}
}); });
} }
@ -50,7 +52,7 @@ class Category extends Model
{ {
$value = $value ? $value : $data['type']; $value = $value ? $value : $data['type'];
$list = $this->getTypeList(); $list = $this->getTypeList();
return isset($list[$value]) ? $list[$value] : ''; return $list[$value] ?? '';
} }
public function getFlagList() public function getFlagList()

View File

@ -115,8 +115,8 @@ class Config extends Model
$data = $result; $data = $result;
} }
$fieldarr = $valuearr = []; $fieldarr = $valuearr = [];
$field = isset($data['field']) ? $data['field'] : (isset($data['key']) ? $data['key'] : []); $field = $data['field'] ?? ($data['key'] ?? []);
$value = isset($data['value']) ? $data['value'] : []; $value = $data['value'] ?? [];
foreach ($field as $m => $n) { foreach ($field as $m => $n) {
if ($n != '') { if ($n != '') {
$fieldarr[] = $field[$m]; $fieldarr[] = $field[$m];
@ -175,7 +175,7 @@ class Config extends Model
if (!preg_match("/^((?:[a-z]+:)?\/\/)(.*)/i", $uploadurl) && substr($uploadurl, 0, 1) !== '/') { if (!preg_match("/^((?:[a-z]+:)?\/\/)(.*)/i", $uploadurl) && substr($uploadurl, 0, 1) !== '/') {
$uploadurl = url($uploadurl, '', false); $uploadurl = url($uploadurl, '', false);
} }
$uploadcfg['fullmode'] = isset($uploadcfg['fullmode']) && $uploadcfg['fullmode'] ? true : false; $uploadcfg['fullmode'] = isset($uploadcfg['fullmode']) && $uploadcfg['fullmode'];
$uploadcfg['thumbstyle'] = $uploadcfg['thumbstyle'] ?? ''; $uploadcfg['thumbstyle'] = $uploadcfg['thumbstyle'] ?? '';
$upload = [ $upload = [

View File

@ -7,7 +7,7 @@ use think\Model;
/** /**
* 邮箱验证码 * 邮箱验证码
*/ */
class Ems Extends Model class Ems extends Model
{ {
// 开启自动写入时间戳字段 // 开启自动写入时间戳字段
@ -18,5 +18,4 @@ class Ems Extends Model
// 追加属性 // 追加属性
protected $append = [ protected $append = [
]; ];
} }

View File

@ -7,7 +7,7 @@ use think\Model;
/** /**
* 会员余额日志模型 * 会员余额日志模型
*/ */
class MoneyLog Extends Model class MoneyLog extends Model
{ {
// 表名 // 表名

View File

@ -7,7 +7,7 @@ use think\Model;
/** /**
* 会员积分日志模型 * 会员积分日志模型
*/ */
class ScoreLog Extends Model class ScoreLog extends Model
{ {
// 表名 // 表名

View File

@ -7,7 +7,7 @@ use think\Model;
/** /**
* 短信验证码 * 短信验证码
*/ */
class Sms Extends Model class Sms extends Model
{ {
// 开启自动写入时间戳字段 // 开启自动写入时间戳字段
@ -18,5 +18,4 @@ class Sms Extends Model
// 追加属性 // 追加属性
protected $append = [ protected $append = [
]; ];
} }

View File

@ -0,0 +1 @@
页面未找到

View File

@ -19,7 +19,7 @@ if (isset($_GET['lang'])) {
$langSet = strtolower($_COOKIE['think_var']); $langSet = strtolower($_COOKIE['think_var']);
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
$langSet = strtolower($matches[1]); $langSet = strtolower($matches[1] ?? '');
} }
$langSet = $langSet && in_array($langSet, ['zh-cn', 'en']) ? $langSet : 'zh-cn'; $langSet = $langSet && in_array($langSet, ['zh-cn', 'en']) ? $langSet : 'zh-cn';
$langSet == 'en' && $lang = array_combine(array_keys($lang), array_keys($lang)); $langSet == 'en' && $lang = array_combine(array_keys($lang), array_keys($lang));

View File

@ -42,7 +42,7 @@ return [
// 默认时区 // 默认时区
'default_timezone' => 'PRC', 'default_timezone' => 'PRC',
// 是否开启多语言 // 是否开启多语言
'lang_switch_on' => true, 'lang_switch_on' => false,
// 默认全局过滤方法 用逗号分隔多个 // 默认全局过滤方法 用逗号分隔多个
'default_filter' => '', 'default_filter' => '',
// 默认语言 // 默认语言
@ -151,6 +151,11 @@ return [
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// 异常页面的模板文件 // 异常页面的模板文件
'exception_tmpl' => APP_PATH . 'common' . DS . 'view' . DS . 'tpl' . DS . 'think_exception.tpl', 'exception_tmpl' => APP_PATH . 'common' . DS . 'view' . DS . 'tpl' . DS . 'think_exception.tpl',
// 自定义错误码模板
'http_exception_template' => [
// 定义404错误的模板渲染
// 404 => APP_PATH . 'common/view/tpl/404.tpl',
],
// 错误显示信息,非调试模式有效 // 错误显示信息,非调试模式有效
'error_message' => '你所浏览的页面暂时无法访问', 'error_message' => '你所浏览的页面暂时无法访问',
// 显示错误信息 // 显示错误信息
@ -201,6 +206,7 @@ return [
'type' => '', 'type' => '',
// 是否自动开启 SESSION // 是否自动开启 SESSION
'auto_start' => true, 'auto_start' => true,
//'cache_limiter'=>''
], ],
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Cookie设置 // | Cookie设置
@ -296,7 +302,7 @@ return [
//允许跨域的域名,多个以,分隔 //允许跨域的域名,多个以,分隔
'cors_request_domain' => 'localhost,127.0.0.1', 'cors_request_domain' => 'localhost,127.0.0.1',
//版本号 //版本号
'version' => '1.3.4.20220530', 'version' => '1.5.2.20240906',
//API接口地址 //API接口地址
'api_url' => 'https://api.fastadmin.net', 'api_url' => 'https://api.fastadmin.net',
], ],

View File

@ -0,0 +1,12 @@
<?php
return [
'connector' => 'Redis', // Redis 驱动
'expire' => 0, // 任务的过期时间默认为60秒; 若要禁用,则设置为 null
'default' => 'default', // 默认的队列名称
'host' => '127.0.0.1', // redis 主机ip
'port' => 6379, // redis 端口
'password' => '', // redis 密码
'select' => 0, // 使用哪一个 db默认为 db0
'timeout' => 0, // redis连接的超时时间
'persistent' => false,
];

View File

@ -33,8 +33,8 @@ return [
'mail_type' => '1', 'mail_type' => '1',
'mail_smtp_host' => 'smtp.qq.com', 'mail_smtp_host' => 'smtp.qq.com',
'mail_smtp_port' => '465', 'mail_smtp_port' => '465',
'mail_smtp_user' => '10000', 'mail_smtp_user' => '',
'mail_smtp_pass' => 'password', 'mail_smtp_pass' => '',
'mail_verify_type' => '2', 'mail_verify_type' => '2',
'mail_from' => '10000@qq.com', 'mail_from' => '',
]; ];

View File

@ -21,7 +21,7 @@ return [
/** /**
* 可上传的文件类型 * 可上传的文件类型
*/ */
'mimetype' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,xls,xlsx,wav,mp4,mp3,webm,pdf', 'mimetype' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3,webm',
/** /**
* 是否支持批量上传 * 是否支持批量上传
*/ */

View File

@ -4,6 +4,7 @@ namespace app\index\controller;
use app\common\controller\Frontend; use app\common\controller\Frontend;
use think\Lang; use think\Lang;
use think\Loader;
use think\Response; use think\Response;
/** /**
@ -22,6 +23,7 @@ class Ajax extends Frontend
*/ */
public function lang() public function lang()
{ {
$this->request->get(['callback' => 'define']);
$header = ['Content-Type' => 'application/javascript']; $header = ['Content-Type' => 'application/javascript'];
if (!config('app_debug')) { if (!config('app_debug')) {
$offset = 30 * 60 * 60 * 24; // 缓存一个月 $offset = 30 * 60 * 60 * 24; // 缓存一个月
@ -30,8 +32,20 @@ class Ajax extends Frontend
$header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; $header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
} }
$controllername = $this->request->get('controllername');
$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");
$this->loadlang($controllername); $className = Loader::parseClass($this->request->module(), 'controller', $controllername, false);
//存在对应的类才加载
if (class_exists($className)) {
$this->loadlang($controllername);
}
//强制输出JSON Object //强制输出JSON Object
return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]); return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
} }

View File

@ -65,13 +65,13 @@ class User extends Frontend
*/ */
public function register() public function register()
{ {
$url = $this->request->request('url', '', 'trim'); $url = $this->request->request('url', '', 'url_clean');
if ($this->auth->id) { if ($this->auth->id) {
$this->success(__('You\'ve logged in, do not login again'), $url ? $url : url('user/index')); $this->success(__('You\'ve logged in, do not login again'), $url ? $url : url('user/index'));
} }
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);
$email = $this->request->post('email'); $email = $this->request->post('email');
$mobile = $this->request->post('mobile', ''); $mobile = $this->request->post('mobile', '');
$captcha = $this->request->post('captcha'); $captcha = $this->request->post('captcha');
@ -128,9 +128,8 @@ class User extends Frontend
} }
} }
//判断来源 //判断来源
$referer = $this->request->server('HTTP_REFERER'); $referer = $this->request->server('HTTP_REFERER', '', 'url_clean');
if (!$url && (strtolower(parse_url($referer, PHP_URL_HOST)) == strtolower($this->request->host())) if (!$url && $referer && !preg_match("/(user\/login|user\/register|user\/logout)/i", $referer)) {
&& !preg_match("/(user\/login|user\/register|user\/logout)/i", $referer)) {
$url = $referer; $url = $referer;
} }
$this->view->assign('captchaType', config('fastadmin.user_register_captcha')); $this->view->assign('captchaType', config('fastadmin.user_register_captcha'));
@ -144,13 +143,13 @@ class User extends Frontend
*/ */
public function login() public function login()
{ {
$url = $this->request->request('url', '', 'trim'); $url = $this->request->request('url', '', 'url_clean');
if ($this->auth->id) { if ($this->auth->id) {
$this->success(__('You\'ve logged in, do not login again'), $url ? $url : url('user/index')); $this->success(__('You\'ve logged in, do not login again'), $url ?: url('user/index'));
} }
if ($this->request->isPost()) { if ($this->request->isPost()) {
$account = $this->request->post('account'); $account = $this->request->post('account');
$password = $this->request->post('password'); $password = $this->request->post('password', '', null);
$keeplogin = (int)$this->request->post('keeplogin'); $keeplogin = (int)$this->request->post('keeplogin');
$token = $this->request->post('__token__'); $token = $this->request->post('__token__');
$rule = [ $rule = [
@ -174,7 +173,6 @@ class User extends Frontend
$result = $validate->check($data); $result = $validate->check($data);
if (!$result) { if (!$result) {
$this->error(__($validate->getError()), null, ['token' => $this->request->token()]); $this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return false;
} }
if ($this->auth->login($account, $password)) { if ($this->auth->login($account, $password)) {
$this->success(__('Logged in successful'), $url ? $url : url('user/index')); $this->success(__('Logged in successful'), $url ? $url : url('user/index'));
@ -183,9 +181,8 @@ class User extends Frontend
} }
} }
//判断来源 //判断来源
$referer = $this->request->server('HTTP_REFERER'); $referer = $this->request->server('HTTP_REFERER', '', 'url_clean');
if (!$url && (strtolower(parse_url($referer, PHP_URL_HOST)) == strtolower($this->request->host())) if (!$url && $referer && !preg_match("/(user\/login|user\/register|user\/logout)/i", $referer)) {
&& !preg_match("/(user\/login|user\/register|user\/logout)/i", $referer)) {
$url = $referer; $url = $referer;
} }
$this->view->assign('url', $url); $this->view->assign('url', $url);
@ -225,9 +222,9 @@ class User extends Frontend
public function changepwd() public function changepwd()
{ {
if ($this->request->isPost()) { if ($this->request->isPost()) {
$oldpassword = $this->request->post("oldpassword"); $oldpassword = $this->request->post("oldpassword", '', null);
$newpassword = $this->request->post("newpassword"); $newpassword = $this->request->post("newpassword", '', null);
$renewpassword = $this->request->post("renewpassword"); $renewpassword = $this->request->post("renewpassword", '', null);
$token = $this->request->post('__token__'); $token = $this->request->post('__token__');
$rule = [ $rule = [
'oldpassword' => 'require|regex:\S{6,30}', 'oldpassword' => 'require|regex:\S{6,30}',
@ -254,7 +251,6 @@ class User extends Frontend
$result = $validate->check($data); $result = $validate->check($data);
if (!$result) { if (!$result) {
$this->error(__($validate->getError()), null, ['token' => $this->request->token()]); $this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return false;
} }
$ret = $this->auth->changepwd($newpassword, $oldpassword); $ret = $this->auth->changepwd($newpassword, $oldpassword);

View File

@ -23,7 +23,7 @@ return [
'Email active successful' => '邮箱激活成功', 'Email active successful' => '邮箱激活成功',
'Username can not be empty' => '用户名不能为空', 'Username can not be empty' => '用户名不能为空',
'Username must be 3 to 30 characters' => '用户名必须3-30个字符', 'Username must be 3 to 30 characters' => '用户名必须3-30个字符',
'Username must be 6 to 30 characters' => '用户名必须3-30个字符', 'Username must be 6 to 30 characters' => '用户名必须6-30个字符',
'Account must be 3 to 50 characters' => '账户必须3-50个字符', 'Account must be 3 to 50 characters' => '账户必须3-50个字符',
'Password can not be empty' => '密码不能为空', 'Password can not be empty' => '密码不能为空',
'Password must be 6 to 30 characters' => '密码必须6-30个字符', 'Password must be 6 to 30 characters' => '密码必须6-30个字符',
@ -60,6 +60,8 @@ return [
'Logged in successful' => '登录成功', 'Logged in successful' => '登录成功',
'Logout successful' => '退出成功', 'Logout successful' => '退出成功',
'User center already closed' => '会员中心已经关闭', 'User center already closed' => '会员中心已经关闭',
'Don\'t have an account? Sign up' => '还没有账号?点击注册',
'Already have an account? Sign in' => '已经有账号?点击登录',
'Operation failed' => '操作失败', 'Operation failed' => '操作失败',
'Invalid parameters' => '参数不正确', 'Invalid parameters' => '参数不正确',
'Change password failure' => '修改密码失败', 'Change password failure' => '修改密码失败',

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@
<span class="visible-xs-inline-block" style="padding:5px;">{$user.nickname} <b class="caret"></b></span> <span class="visible-xs-inline-block" style="padding:5px;">{$user.nickname} <b class="caret"></b></span>
</a> </a>
{else /} {else /}
<a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown">{:__('User center')} <b class="caret"></b></a> <a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown">{:__('Member center')} <b class="caret"></b></a>
{/if} {/if}
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{if $user} {if $user}

View File

@ -24,26 +24,21 @@
<a href="{:url('user/profile')}" class="btn btn-primary pull-right"><i class="fa fa-pencil"></i> {:__('Profile')}</a> <a href="{:url('user/profile')}" class="btn btn-primary pull-right"><i class="fa fa-pencil"></i> {:__('Profile')}</a>
</h2> </h2>
<div class="row user-baseinfo"> <div class="row user-baseinfo">
<div class="col-md-3 col-sm-3 col-xs-2 text-center user-center"> <div class="col-md-3 col-sm-3 col-xs-3 text-center user-center">
<a href="{:url('user/profile')}" title="{:__('Click to edit')}"> <a href="{:url('user/profile')}" title="{:__('Click to edit')}">
<span class="avatar-img"><img src="{$user.avatar|htmlentities|cdnurl}" alt=""></span> <span class="avatar-img"><img src="{$user.avatar|htmlentities|cdnurl}" alt=""></span>
</a> </a>
</div> </div>
<div class="col-md-9 col-sm-9 col-xs-10"> <div class="col-md-9 col-sm-9 col-xs-9">
<!-- Content -->
<div class="ui-content"> <div class="ui-content">
<!-- Heading -->
<h4><a href="{:url('user/profile')}">{$user.nickname|htmlentities}</a></h4> <h4><a href="{:url('user/profile')}">{$user.nickname|htmlentities}</a></h4>
<!-- Paragraph -->
<p class="text-muted"> <p class="text-muted">
{$user.bio|default=__("This guy hasn't written anything yet")|htmlentities} {$user.bio|default=__("This guy hasn't written anything yet")|htmlentities}
</p> </p>
<!-- Success -->
</div> </div>
</div> </div>
<div class="col-md-9 col-sm-9 col-xs-12"> <div class="col-md-9 col-sm-9 col-xs-12">
<!-- Content -->
<div class="ui-content"> <div class="ui-content">
<div class="basicinfo"> <div class="basicinfo">
<div class="row"> <div class="row">
@ -56,12 +51,6 @@
<a href="javascript:;" class="viewscore">{$user.score}</a> <a href="javascript:;" class="viewscore">{$user.score}</a>
</div> </div>
</div> </div>
<div class="row">
<div class="col-xs-4 col-md-2">{:__('Successions')}</div>
<div class="col-xs-8 col-md-4">{$user.successions} {:__('Day')}</div>
<div class="col-xs-4 col-md-2">{:__('Maxsuccessions')}</div>
<div class="col-xs-8 col-md-4">{$user.maxsuccessions} {:__('Day')}</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-4 col-md-2">{:__('Logintime')}</div> <div class="col-xs-4 col-md-2">{:__('Logintime')}</div>
<div class="col-xs-8 col-md-4">{$user.logintime|date="Y-m-d H:i:s",###}</div> <div class="col-xs-8 col-md-4">{$user.logintime|date="Y-m-d H:i:s",###}</div>

View File

@ -31,7 +31,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Sign in')}</button> <button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Sign in')}</button>
<a href="{:url('user/register')}?url={$url|urlencode|htmlentities}" class="btn btn-default btn-lg btn-block mt-3 no-border">还没有账号?点击注册</a> <a href="{:url('user/register')}?url={$url|urlencode|htmlentities}" class="btn btn-default btn-lg btn-block mt-3 no-border">{:__("Don't have an account? Sign up")}</a>
</div> </div>
<!--@IndexLoginFormEnd--> <!--@IndexLoginFormEnd-->
</form> </form>
@ -86,8 +86,7 @@
</div> </div>
</div> </div>
<div class="form-group form-footer"> <div class="form-group form-footer">
<label class="control-label col-xs-12 col-sm-3"></label> <div class="col-xs-12 col-sm-8 col-sm-offset-3">
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-md btn-primary">{:__('Ok')}</button> <button type="submit" class="btn btn-md btn-primary">{:__('Ok')}</button>
</div> </div>
</div> </div>

View File

@ -132,8 +132,7 @@
</div> </div>
<div class="form-footer"> <div class="form-footer">
<div class="form-group" style="margin-bottom:0;"> <div class="form-group" style="margin-bottom:0;">
<label class="control-label col-xs-12 col-sm-3"></label> <div class="col-xs-12 col-sm-8 col-sm-offset-3">
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-md btn-primary">{:__('Submit')}</button> <button type="submit" class="btn btn-md btn-primary">{:__('Submit')}</button>
</div> </div>
</div> </div>
@ -166,8 +165,7 @@
</div> </div>
<div class="form-footer"> <div class="form-footer">
<div class="form-group" style="margin-bottom:0;"> <div class="form-group" style="margin-bottom:0;">
<label class="control-label col-xs-12 col-sm-3"></label> <div class="col-xs-12 col-sm-8 col-sm-offset-3">
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-md btn-primary">{:__('Submit')}</button> <button type="submit" class="btn btn-md btn-primary">{:__('Submit')}</button>
</div> </div>
</div> </div>

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