Compare commits

...

251 Commits
v6 ... v6.1.2

Author SHA1 Message Date
邹景立
d9436f7b98 Update readme.md 2023-02-18 22:25:02 +08:00
邹景立
9d7dc9e26b 修改文档文件 2023-02-18 22:24:07 +08:00
邹景立
80a724d8ef Update readme.md 2023-02-18 22:21:36 +08:00
邹景立
b8390aea15 Update readme.md 2023-02-18 22:15:02 +08:00
邹景立
97ac2b3bac Update readme.md 2023-02-18 18:55:08 +08:00
邹景立
bf7502788a Update readme.md 2023-02-18 18:53:44 +08:00
邹景立
0f4230b69f Update .gitignore 2023-02-18 18:52:15 +08:00
邹景立
70e3631702 修改项目文档 2023-02-16 14:54:02 +08:00
邹景立
3f532af683 默认只保留 admin 模块 2023-02-16 14:44:53 +08:00
邹景立
88751808e0 Update readme.md 2023-02-15 11:34:45 +08:00
邹景立
d17430c97f Update readme.md 2023-02-15 11:28:38 +08:00
邹景立
5613c16d50 Update readme.md 2023-02-15 11:28:12 +08:00
邹景立
2c553ca8a9 Update readme.md 2023-02-15 11:27:28 +08:00
邹景立
a7e2b2b0ac Update readme.md 2023-02-15 11:19:05 +08:00
邹景立
02f7aa7962 Update readme.md 2023-02-15 11:12:31 +08:00
邹景立
7df16fb364 Update readme.md 2023-02-15 11:10:09 +08:00
邹景立
1e986f331b Update readme.md 2023-02-15 11:08:14 +08:00
邹景立
a2dd4c646f Update readme.md 2023-02-15 11:03:04 +08:00
邹景立
ecfb50a9ac Update readme.md 2023-02-15 10:59:02 +08:00
邹景立
d8a8907b57 修改项目描述 2023-02-15 10:53:57 +08:00
邹景立
7f5b387ace Update readme.md 2023-01-12 16:03:16 +08:00
邹景立
e57bb41588 Update readme.md 2023-01-12 15:58:52 +08:00
邹景立
aa17336fca Update readme.md 2023-01-12 15:58:13 +08:00
邹景立
42c9a06228 Update readme.md 2023-01-12 15:55:57 +08:00
邹景立
0148d85072 Update readme.md 2023-01-12 15:55:07 +08:00
邹景立
ada04f0246 修改项目文档 2023-01-12 15:41:21 +08:00
邹景立
3b85dd82c8 Update readme.md 2023-01-10 23:42:54 +08:00
邹景立
dd286a8747 修改项目描述 2023-01-10 23:41:16 +08:00
邹景立
b0e5e8e8d5 修改项目文档 2023-01-10 23:39:20 +08:00
邹景立
30cd9b9218 修改项目描述文件 2023-01-10 23:31:19 +08:00
邹景立
de741a9878 修改项目描述 2023-01-10 23:28:34 +08:00
邹景立
a181f7c1c0 Update readme.md 2023-01-10 23:26:46 +08:00
邹景立
c3798c2255 修改项目描述 2023-01-10 23:25:04 +08:00
邹景立
9bd3c21297 排除插件管控的部分本地提交 2023-01-10 23:11:11 +08:00
Anyon
bfe944c663
update composer.json.
Signed-off-by: Anyon <zoujingli@qq.com>
2023-01-10 00:51:05 +00:00
邹景立
fbdd008828 Update readme.md 2023-01-09 22:30:01 +08:00
邹景立
74f4484c59 Update readme.md 2023-01-09 22:25:08 +08:00
邹景立
2b40fdad93 Update readme.md 2023-01-09 11:31:29 +08:00
邹景立
19a92b4a16 修改项目描述 2023-01-09 11:23:02 +08:00
邹景立
8cc632c3de Update readme.md 2023-01-06 11:22:05 +08:00
邹景立
9f253a75bc Update readme.md 2023-01-05 23:57:37 +08:00
邹景立
32be486825 修改 2023-01-05 19:07:38 +08:00
邹景立
ec4e26ae45 切换为正式版本插件 2023-01-05 17:12:26 +08:00
邹景立
3b4b462a76 Update readme.md 2023-01-05 16:37:58 +08:00
邹景立
be01a6f449 修改项目描述 2023-01-05 16:35:55 +08:00
邹景立
732f7e8b53 Update readme.md 2023-01-05 16:07:26 +08:00
邹景立
44400b039b Update readme.md 2023-01-05 16:01:56 +08:00
邹景立
44f8407aef 修改项目描述 2023-01-05 15:59:27 +08:00
邹景立
0ad33cda04 Update readme.md 2023-01-04 19:57:43 +08:00
邹景立
4632ebbd7a Update readme.md 2023-01-04 18:30:33 +08:00
邹景立
bda62319a2 Update readme.md 2023-01-04 18:29:33 +08:00
邹景立
c2030658c2 Update readme.md 2023-01-04 18:25:39 +08:00
邹景立
d2b0185eb5 修改项目组件配置 2023-01-04 18:03:21 +08:00
邹景立
8baf6877b0 增加开源协议 2023-01-04 10:26:25 +08:00
邹景立
c0f019cd9c Update composer.json 2023-01-03 01:05:42 +08:00
邹景立
cb47bd0e53 Update composer.json 2023-01-03 00:26:05 +08:00
邹景立
1c958dce85 Update composer.json 2023-01-03 00:25:56 +08:00
邹景立
aa8480ae37 Update composer.json 2023-01-02 00:30:01 +08:00
邹景立
33f0574bcd Update composer.json 2023-01-02 00:16:18 +08:00
邹景立
082ac9d5c4 Update composer.json 2023-01-01 23:20:47 +08:00
邹景立
9180fb3e45 Revert "修改版本依赖"
This reverts commit a31d5f62e7aded5cbc3324f70dc4a25ac8a85b11.
2023-01-01 23:19:24 +08:00
邹景立
a31d5f62e7 修改版本依赖 2023-01-01 22:57:02 +08:00
邹景立
a3067ab5fb Update readme.md 2022-12-30 15:01:33 +08:00
邹景立
7c79fe377b 初始化 dev 分支代码 2022-12-30 14:58:34 +08:00
邹景立
075c00fbf7 Update admin.js 2022-12-06 15:32:00 +08:00
邹景立
ba998bdb4b 去除对 admin view 的依赖 2022-11-30 11:10:44 +08:00
邹景立
54bdb10d82 Update app.php 2022-11-30 11:09:28 +08:00
邹景立
6f66ee345d Update composer.json 2022-11-29 15:40:35 +08:00
邹景立
99046439d4 文件上传,增加删除 change 事件 2022-11-28 15:14:53 +08:00
Anyon
0a51f6bb78
删除文件 app/center/controller 2022-11-27 14:41:20 +00:00
邹景立
cfcb183117 Update composer.json 2022-11-27 21:56:00 +08:00
邹景立
c8f0343c2c Update Index.php 2022-11-27 16:34:48 +08:00
邹景立
649e6757f1 增加 Center 模块 2022-11-27 15:59:40 +08:00
邹景立
542ffc845d 修改运行时间+内存限制 2022-11-22 10:13:42 +08:00
邹景立
d92749b7d7 Update form_wechat.html 2022-11-21 17:08:26 +08:00
邹景立
b7b3610b54 修改微信支付 2022-11-21 16:15:52 +08:00
邹景立
f00f9f629e 修改支付 2022-11-21 15:00:12 +08:00
邹景立
294c8b82a6 Update Plugs.php 2022-11-21 12:45:48 +08:00
邹景立
6cbb687862 优化后台判断与Library配合 2022-11-21 12:42:23 +08:00
邹景立
90228f0ff6 修改系统运行服务 2022-11-21 11:40:25 +08:00
邹景立
983496fd9c Update Login.php 2022-11-21 11:30:26 +08:00
邹景立
6ae1789cc5 Update system.html 2022-11-17 18:43:22 +08:00
邹景立
d8b2170555 Update system.html 2022-11-17 18:39:24 +08:00
邹景立
36ce2c7654 Update system.html 2022-11-17 18:38:57 +08:00
邹景立
84379c459f Update app.php 2022-11-17 18:25:53 +08:00
邹景立
1e46a7fad2 Update Login.php 2022-11-17 16:53:41 +08:00
邹景立
a3fad57138 Update phinx.php 2022-11-16 18:00:28 +08:00
邹景立
3d9836d5d5 Update admin.js 2022-11-16 14:57:38 +08:00
邹景立
88e8b5d4a3 Update phinx.php 2022-11-16 11:58:19 +08:00
邹景立
c3dcb3a9f6 增加备份配置 2022-11-16 11:56:23 +08:00
邹景立
4f8e4bf443 Update app.php 2022-11-16 11:54:48 +08:00
邹景立
5e153a92a9 Update lang.php 2022-11-16 11:54:03 +08:00
邹景立
d32c23432d 同步配置 2022-11-16 11:52:35 +08:00
邹景立
a47ef73a5b 修改微信表单 2022-11-15 17:08:06 +08:00
邹景立
ea4e646185 同步升级脚本 2022-11-15 17:00:40 +08:00
邹景立
1809e34661 同步升级layui 2022-11-14 18:00:22 +08:00
邹景立
c2b887cc45 Update readme.md 2022-11-13 15:09:41 +08:00
邹景立
9bae4fbf6a Update readme.md 2022-11-13 15:01:53 +08:00
邹景立
d84ec4fe6c Update readme.md 2022-11-13 14:49:55 +08:00
邹景立
6a41175e1d Update readme.md 2022-11-13 14:48:36 +08:00
邹景立
44950d42c0 Update readme.md 2022-11-13 14:47:52 +08:00
邹景立
642d73fbe8 Update readme.md 2022-11-13 12:37:58 +08:00
邹景立
0653cfcc4a 修改文档描述 2022-11-13 12:34:51 +08:00
邹景立
ed74e6b8ad 同步跟进Library调整 2022-11-13 12:10:28 +08:00
邹景立
593316a927 修改模板文件 2022-11-12 18:19:22 +08:00
邹景立
02a1c421f4 修改项目描述 2022-11-12 18:14:45 +08:00
邹景立
8126c17197 修改用户资料更新 2022-11-12 18:12:23 +08:00
邹景立
ccd6d15bfb 修改数据库脚本 2022-11-10 12:10:52 +08:00
邹景立
9f2b4a6b46 修改支付宝支付 2022-11-09 17:48:13 +08:00
邹景立
c1e26665bf 修正支持 2022-11-09 17:15:40 +08:00
邹景立
b4d3be8785 优化管理样式 2022-11-09 10:51:39 +08:00
邹景立
7e8e721883 升级Layui版本,优化视频上传 2022-11-09 10:36:25 +08:00
邹景立
cfb3ff4938 Update .gitignore 2022-11-05 14:34:23 +08:00
邹景立
bf6220d35f 修改样式 2022-11-05 10:50:42 +08:00
邹景立
9326343474 Update admin.js 2022-11-05 10:36:30 +08:00
邹景立
7d778dc406 修改数据库 2022-11-04 15:03:34 +08:00
邹景立
2efa2ebb33 修改数据库 2022-11-04 14:50:30 +08:00
邹景立
2cd8bd973a Update 20221013045829_install_wechat.php 2022-11-04 11:42:38 +08:00
邹景立
790e0799ba Update 20221013045838_install_user.php 2022-11-04 11:41:00 +08:00
邹景立
eccba878bb 修改数据库 2022-11-04 11:39:12 +08:00
邹景立
ef9f90288d Update composer.json 2022-11-03 11:05:35 +08:00
邹景立
8ae4647205 优化路径计算 2022-11-03 10:27:30 +08:00
邹景立
c83bf37ac8 Update UserTransfer.php 2022-11-03 10:23:31 +08:00
邹景立
734c0fda04 增加notify提示 2022-11-03 10:15:19 +08:00
邹景立
191b4b6f38 Update Index.php 2022-11-02 17:47:14 +08:00
邹景立
fe3b002fa4 Update readme.md 2022-11-02 14:09:18 +08:00
邹景立
55c1dc17b3 修改文档 2022-11-02 14:06:08 +08:00
邹景立
9b5239ece8 增加数据库类型显示 2022-11-02 10:37:19 +08:00
邹景立
cb1a1a263a Update WechatPaymentService.php 2022-10-28 17:51:38 +08:00
邹景立
ae8d38b509 修正微信二信码支付 2022-10-28 17:47:33 +08:00
邹景立
9f1687f08c Merge branch 'v6' into dev 2022-10-28 12:38:13 +08:00
邹景立
f371d9ca4b 优化文件上传 2022-10-28 11:39:26 +08:00
邹景立
a2423ec433 优化视频文件上传 2022-10-28 11:25:31 +08:00
邹景立
7d4983ca43 修改数据库管理 2022-10-28 10:50:11 +08:00
邹景立
58bbd06e15 修改数据库 2022-10-28 10:49:12 +08:00
邹景立
9eb6077149 修改数据库 2022-10-28 10:22:53 +08:00
邹景立
06ed50c94c 修改数据库管理 2022-10-27 15:14:36 +08:00
邹景立
e270e81223 Update Fans.php 2022-10-27 15:00:55 +08:00
邹景立
b8ad663178 修改数据表 2022-10-27 14:59:44 +08:00
邹景立
3d5f8afc1b 修改菜单规则 2022-10-27 14:58:45 +08:00
邹景立
c876adb1e9 修改数据 库 2022-10-27 14:54:28 +08:00
邹景立
d3d397ab9a 初始化 2022-10-27 14:53:18 +08:00
邹景立
e0e71532fa 修改菜单 2022-10-27 14:50:59 +08:00
邹景立
823780bdb2 Delete default.php 2022-10-27 13:55:30 +08:00
邹景立
484e9d9d19 修改配置 2022-10-27 13:51:21 +08:00
邹景立
30274cffeb 修改注释 2022-10-27 13:50:11 +08:00
邹景立
2e5759fce5 Update 20221013031926_install_admin_data.php 2022-10-27 13:49:04 +08:00
邹景立
5217883a26 Update 20221013031926_install_admin_data.php 2022-10-27 13:48:26 +08:00
邹景立
3e6189ceb7 修改数据库 2022-10-27 13:47:36 +08:00
邹景立
804889743a 修改数据文件 2022-10-27 13:45:05 +08:00
邹景立
4424958455 修改数据库 2022-10-27 13:43:04 +08:00
邹景立
2f0aadbe65 Update 20221013045839_install_user_data.php 2022-10-27 11:53:42 +08:00
邹景立
4c694cffc6 Update 20221013045840_install_shop.php 2022-10-27 11:50:33 +08:00
邹景立
e6cd7009d3 修改数据库 2022-10-27 11:50:00 +08:00
邹景立
5014ccabff Create 20221013045839_install_user_data.php 2022-10-27 11:42:12 +08:00
邹景立
258611060f Update 20221013045830_install_wechat_data.php 2022-10-27 11:33:20 +08:00
邹景立
f518828cdc 创建数据库 2022-10-27 11:29:24 +08:00
邹景立
d72c26cba7 修改ck编辑器,去除源码编辑模式 2022-10-27 10:13:08 +08:00
邹景立
01ef5bc0f5 Update .gitignore 2022-10-26 15:07:28 +08:00
邹景立
f277d5fda3 修改文件 2022-10-26 13:25:02 +08:00
邹景立
18690abcec 去除 flysystem 配置 2022-10-26 13:25:02 +08:00
邹景立
5474c0cc8d Update UserTokenService.php 2022-10-26 13:25:02 +08:00
邹景立
f25bbb8c85 Update UserTokenService.php 2022-10-26 13:25:02 +08:00
邹景立
b95f248c33 修改注释 2022-10-26 13:25:02 +08:00
邹景立
646baba0aa Update Wxapp.php 2022-10-26 13:25:02 +08:00
邹景立
eb96f143c2 Update Login.php 2022-10-25 17:40:35 +08:00
邹景立
c5083b4f82 Update File.php 2022-10-25 17:38:28 +08:00
邹景立
24ba7a3289 Update Config.php 2022-10-25 17:35:41 +08:00
邹景立
62d5037f4e Update .gitignore 2022-10-25 16:36:51 +08:00
邹景立
cc3e774ae8 Update .gitignore 2022-10-25 16:35:36 +08:00
邹景立
5c97e7149c Update .gitignore 2022-10-25 16:35:25 +08:00
邹景立
180f044e37 Merge branch 'dev' of https://gitee.com/zoujingli/ThinkAdmin into dev 2022-10-25 15:04:33 +08:00
邹景立
6f2d88e27a 修改代码 2022-10-25 14:57:06 +08:00
Anyon
9a97bdb8ab 修正七牛云存储配置 2022-10-24 14:57:31 +08:00
Anyon
35b5999f60 Update upload.js 2022-10-21 17:55:57 +08:00
Anyon
45ec382ddc 修改图片限制 2022-10-21 17:54:19 +08:00
Anyon
21b9e107c5 修改文件大小限制 2022-10-21 17:51:01 +08:00
Anyon
85b8c55b0a Update index.html 2022-10-21 14:49:16 +08:00
Anyon
423a12e569 修改任务 2022-10-21 14:45:34 +08:00
Anyon
825163364b 同步升级组件 6.0.39 2022-10-20 18:10:11 +08:00
邹景立
52d11305a2 Update Queue.php 2022-10-19 17:02:55 +08:00
邹景立
48c49d6d01 修改函数名 2022-10-19 13:30:53 +08:00
邹景立
4455a2224b 修改配置文件 2022-10-19 12:45:16 +08:00
邹景立
5fb289558b 修改文件管理 2022-10-19 11:40:35 +08:00
邹景立
4f3e8ac8a9 Update form.html 2022-10-19 11:39:28 +08:00
邹景立
569e2338e3 Update index.html 2022-10-19 11:18:57 +08:00
邹景立
179928801d Update readme.md 2022-10-19 11:08:48 +08:00
邹景立
cf7c4b6c34 Update 20221013031925_install_admin.php 2022-10-19 11:08:09 +08:00
邹景立
7ad9baa59c Update ShopGoodsItem.php 2022-10-18 13:30:12 +08:00
邹景立
1368f1e986 Update ShopOrderItem.php 2022-10-18 13:28:27 +08:00
邹景立
ac664a269d Update ShopOrderItem.php 2022-10-18 13:28:06 +08:00
邹景立
c10936ab9e 修改订单模型 2022-10-18 13:26:40 +08:00
邹景立
9bbe01a4b8 修改注释 2022-10-18 13:22:03 +08:00
邹景立
3a0f5b1953 增加异常trace记录 2022-10-18 13:17:37 +08:00
邹景立
28818bc8e1 修改注释 2022-10-18 13:02:21 +08:00
邹景立
b6a0db5b74 增加文件编辑 2022-10-18 11:18:30 +08:00
邹景立
93ecdbf432 修改消息处理 2022-10-18 11:10:31 +08:00
邹景立
17a27b59ed 修改字段文件 2022-10-17 18:25:52 +08:00
邹景立
42a842f90c 修改字段文件 2022-10-17 18:23:42 +08:00
邹景立
0ae6f142fd 修改数据库字段 2022-10-17 18:22:10 +08:00
邹景立
fc824777ab Update image.html 2022-10-17 18:17:29 +08:00
邹景立
13c505bb03 Update image.html 2022-10-17 18:15:31 +08:00
邹景立
2e2c8e1b49 优化图片选择器 2022-10-17 18:09:55 +08:00
邹景立
e61f624ce6 升级文本编辑器 2022-10-17 11:51:51 +08:00
邹景立
54bfcfa4ba 修改样式 2022-10-17 11:46:49 +08:00
邹景立
dbf43b440b 升级 layui 版本 2022-10-17 11:40:35 +08:00
邹景立
4740c66768 Update Base.php 2022-10-17 11:37:42 +08:00
邹景立
b597feb6df Update Queue.php 2022-10-17 11:32:42 +08:00
邹景立
28f7aef0b7 Update 20221013031925_install_admin.php 2022-10-14 15:25:29 +08:00
邹景立
9dbaf69695 Update 20221013045829_install_wechat.php 2022-10-14 15:13:11 +08:00
邹景立
34262095fe 修改数据库文件 2022-10-14 13:10:17 +08:00
邹景立
1041c43fb1 增加数据库索引 2022-10-14 10:51:46 +08:00
邹景立
4940a6be9c 增加数据库索引 2022-10-14 10:45:53 +08:00
邹景立
3d7aad2172 Update readme.md 2022-10-13 22:29:21 +08:00
邹景立
d5ab364422 Update readme.md 2022-10-13 22:28:28 +08:00
邹景立
0f035d771b Update readme.md 2022-10-13 22:28:05 +08:00
邹景立
aca4c270c0 Update readme.md 2022-10-13 22:27:25 +08:00
邹景立
5cd53110a3 Update readme.md 2022-10-13 22:24:05 +08:00
邹景立
7bf956c030 Update 20221013031925_install_admin.php 2022-10-13 22:01:25 +08:00
邹景立
951133fa8b 修改数据库 2022-10-13 21:56:39 +08:00
邹景立
b44a92ba76 Update index.html 2022-10-13 21:48:32 +08:00
邹景立
ef35f1d616 修改数据库 2022-10-13 19:52:42 +08:00
邹景立
c67ced5b54 修改数据库 2022-10-13 19:50:05 +08:00
邹景立
6f0f54845e 合并数据库文件 2022-10-13 19:23:46 +08:00
邹景立
ad17150edb 修改数据库文件 2022-10-13 19:05:23 +08:00
邹景立
ffbb29512f Update 20221013031925_system_auth.php 2022-10-13 18:47:15 +08:00
邹景立
dd81cbf778 Update 20221013045837_base_postage_region.php 2022-10-13 18:44:39 +08:00
邹景立
bb7d78078e Update 20221013045837_base_postage_region.php 2022-10-13 18:40:44 +08:00
邹景立
c57bc6fb26 Update readme.md 2022-10-13 18:34:13 +08:00
邹景立
6f66b5cb3e Update readme.md 2022-10-13 18:31:57 +08:00
邹景立
095017c5f2 Update readme.md 2022-10-13 18:29:04 +08:00
邹景立
e53f6e25f9 删除数据库文件 2022-10-13 18:02:57 +08:00
邹景立
928a4d8122 修改项目文档 2022-10-13 18:02:50 +08:00
邹景立
e0fc5216e6 修改系统兼容 2022-10-13 17:37:20 +08:00
邹景立
191fced9ec 修改数据库 2022-10-13 17:13:26 +08:00
邹景立
6a7c9a2a0b 修改数据库文件 2022-10-13 17:10:09 +08:00
邹景立
a6709b275f 修改数据注释 2022-10-13 17:06:59 +08:00
邹景立
d09a587f03 增加数据库 2022-10-13 16:57:14 +08:00
邹景立
faa066cd44 Create 20221013045836_base_postage_company.php 2022-10-13 15:04:56 +08:00
邹景立
bd0e87a1e7 优化数据文件 2022-10-13 14:46:30 +08:00
邹景立
bffaeb75bb 修改数据库文件 2022-10-13 14:44:33 +08:00
邹景立
7b7dda7827 修改数据文件 2022-10-13 14:40:07 +08:00
邹景立
5900ae17d4 Update 20221013032309_system_auth_node.php 2022-10-13 14:25:33 +08:00
邹景立
6e5816ef67 修改文档名称 2022-10-13 14:22:45 +08:00
邹景立
65314f5aea 增加微信数据库文件 2022-10-13 14:20:24 +08:00
邹景立
224f68ab1b Update 20221013045828_system_user.php 2022-10-13 13:16:33 +08:00
邹景立
5c864c8989 Update 20221013045619_system_queue.php 2022-10-13 13:11:54 +08:00
邹景立
607e13f8e4 完善系统管理数据库 2022-10-13 13:08:22 +08:00
邹景立
e6d809445d 默认使用 sqlite 数据库 2022-10-13 12:48:03 +08:00
邹景立
4d820e1618 增加数据文件 2022-10-13 12:01:15 +08:00
邹景立
03902c68b6 使用数据库迁移工具 2022-10-12 23:33:25 +08:00
694 changed files with 215 additions and 55220 deletions

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
*.js linguist-language=php
*.css linguist-language=php
*.html linguist-language=php

48
.gitignore vendored
View File

@ -2,17 +2,41 @@
.git
.svn
.idea
.fleet
.vscode
*.log
.DS_Store
vendor
runtime
safefile
nbproject
composer.lock
public/upload
public/.user.ini
public/favicon.ico
public/static/theme/css/_*.css*
public/static/theme/css/node_modules
public/static/theme/css/package-lock.json
/vendor
/runtime
/safefile
/nbproject
/composer.lock
!composer.json
/404.html
/.user.ini
/index.html
/public/upload
/public/404.html
/public/.user.ini
/public/index.html
/public/favicon.ico
/database/sqlite.db
think
app/admin
app/wechat
public/index.php
public/router.php
public/static/plugs
public/static/theme
public/static/admin.js
public/static/login.js
/database/migrations/20221013031925_install_admin.php
/database/migrations/20221013031926_install_admin_data.php
/database/migrations/20221013045829_install_wechat.php
/database/migrations/20221013045830_install_wechat_data.php
/database/migrations/20221013045838_install_user.php
/database/migrations/20221013045839_install_user_data.php
/database/migrations/20221013045840_install_user_region.php

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,96 +0,0 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 尝试创建微信自动回复数据表
CREATE TABLE IF NOT EXISTS `wechat_auto`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '类型(text,image,news)',
`time` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '延迟时间',
`code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '消息编号',
`appid` char(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '公众号APPID',
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '文本内容',
`image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '图片链接',
`voice_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '语音链接',
`music_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐标题',
`music_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐链接',
`music_image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '缩略图片',
`music_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '音乐描述',
`video_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频标题',
`video_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频URL',
`video_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '视频描述',
`news_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '图文ID',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0禁用,1启用)',
`create_by` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '创建人',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_wechat_auto_type` (`type`) USING BTREE,
INDEX `idx_wechat_auto_keys` (`time`) USING BTREE,
INDEX `idx_wechat_auto_appid` (`appid`) USING BTREE,
INDEX `idx_wechat_auto_code` (`code`) USING BTREE
) ENGINE = InnoDB
AUTO_INCREMENT = 1
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '微信-回复'
ROW_FORMAT = COMPACT;
-- 调整字段名称长度
ALTER TABLE `system_queue`
MODIFY COLUMN `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务名称' AFTER `code`;
-- 尝试创建数据字典数据表
CREATE TABLE IF NOT EXISTS `system_base`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据类型',
`code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据代码',
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '数据名称',
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '数据内容',
`sort` bigint(20) NULL DEFAULT 0 COMMENT '排序权重',
`status` tinyint(1) NULL DEFAULT 1 COMMENT '数据状态(0禁用,1启动)',
`deleted` tinyint(1) NULL DEFAULT 0 COMMENT '删除状态(0正常,1已删)',
`deleted_at` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '删除时间',
`deleted_by` bigint(20) NULL DEFAULT 0 COMMENT '删除用户',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_system_base_type` (`type`) USING BTREE,
INDEX `idx_system_base_code` (`code`) USING BTREE,
INDEX `idx_system_base_name` (`name`(191)) USING BTREE
) ENGINE = InnoDB
AUTO_INCREMENT = 1
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci COMMENT = '系统-字典'
ROW_FORMAT = COMPACT;
-- 权限表增加身份权限字段
ALTER TABLE `system_user`
ADD COLUMN `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '用户类型' AFTER `id`;
-- 尝试创建系统文件数据表
CREATE TABLE IF NOT EXISTS `system_file` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '上传类型',
`hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '文件哈希',
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '文件名称',
`xext` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '文件后缀',
`xurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '访问链接',
`xkey` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '文件路径',
`mime` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '文件类型',
`size` bigint(20) NULL DEFAULT 0 COMMENT '文件大小',
`uuid` bigint(20) NULL DEFAULT 0 COMMENT '用户编号',
`isfast` tinyint(1) NULL DEFAULT 0 COMMENT '是否秒传',
`issafe` tinyint(1) NULL DEFAULT 0 COMMENT '安全模式',
`status` tinyint(1) NULL DEFAULT 1 COMMENT '上传状态(1悬空,2落地)',
`create_at` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_at` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_system_file_type`(`type`) USING BTREE,
INDEX `idx_system_file_hash`(`hash`) USING BTREE,
INDEX `idx_system_file_uuid`(`uuid`) USING BTREE,
INDEX `idx_system_file_xext`(`xext`) USING BTREE,
INDEX `idx_system_file_status`(`status`) USING BTREE,
INDEX `idx_system_file_issafe`(`issafe`) USING BTREE,
INDEX `idx_system_file_isfast`(`isfast`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统-文件' ROW_FORMAT = COMPACT;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -1,124 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemAuth;
use think\admin\model\SystemNode;
use think\admin\service\AdminService;
/**
* 系统权限管理
* Class Auth
* @package app\admin\controller
*/
class Auth extends Controller
{
/**
* 系统权限管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemAuth::mQuery()->layTable(function () {
$this->title = '系统权限管理';
}, function (QueryHelper $query) {
$query->dateBetween('create_at')->like('title,desc')->equal('status,utype');
});
}
/**
* 添加系统权限
* @auth true
*/
public function add()
{
SystemAuth::mForm('form');
}
/**
* 编辑系统权限
* @auth true
*/
public function edit()
{
SystemAuth::mForm('form');
}
/**
* 修改权限状态
* @auth true
*/
public function state()
{
SystemAuth::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统权限
* @auth true
*/
public function remove()
{
SystemAuth::mDelete();
}
/**
* 权限配置节点
* @auth true
* @throws \ReflectionException
*/
public function apply()
{
$map = $this->_vali(['auth.require#id' => '权限ID不能为空']);
if (input('action') === 'get') {
if ($this->app->isDebug()) AdminService::clearCache();
$nodes = SystemNode::mk()->where($map)->column('node');
$this->success('获取权限节点成功!', AdminService::getTree($nodes));
} elseif (input('action') === 'save') {
[$post, $data] = [$this->request->post(), []];
foreach ($post['nodes'] ?? [] as $node) {
$data[] = ['auth' => $map['auth'], 'node' => $node];
}
SystemNode::mk()->where($map)->delete();
SystemNode::mk()->insertAll($data);
sysoplog('系统权限管理', "配置系统权限[{$map['auth']}]授权成功");
$this->success('访问权限修改成功!', 'javascript:history.back()');
} else {
SystemAuth::mForm('apply');
}
}
/**
* 表单后置数据处理
* @param array $data
*/
protected function _apply_form_filter(array &$data)
{
if ($this->request->isGet()) {
$this->title = "编辑【{$data['title']}】授权";
}
}
}

View File

@ -1,111 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemBase;
/**
* 数据字典管理
* Class Base
* @package app\admin\controller
*/
class Base extends Controller
{
/**
* 数据字典管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemBase::mQuery()->layTable(function () {
$this->title = '数据字典管理';
$this->types = SystemBase::types();
$this->type = $this->get['type'] ?? ($this->types[0] ?? '-');
}, function (QueryHelper $query) {
$query->where(['deleted' => 0])->equal('type');
$query->like('code,name,status')->dateBetween('create_at');
});
}
/**
* 添加数据字典
* @auth true
*/
public function add()
{
SystemBase::mForm('form');
}
/**
* 编辑数据字典
* @auth true
*/
public function edit()
{
SystemBase::mForm('form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DbException
*/
protected function _form_filter(array &$data)
{
if ($this->request->isGet()) {
$this->types = SystemBase::types();
$this->types[] = '--- 新增类型 ---';
$this->type = input('get.type') ?: ($this->types[0] ?? '-');
} else {
$map = [];
$map[] = ['deleted', '=', 0];
$map[] = ['code', '=', $data['code']];
$map[] = ['type', '=', $data['type']];
if (isset($data['id'])) $map[] = ['id', '<>', $data['id']];
if (SystemBase::mk()->where($map)->count() > 0) {
$this->error("同类型的数据编码已经存在!");
}
}
}
/**
* 修改数据状态
* @auth true
*/
public function state()
{
SystemBase::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除数据记录
* @auth true
*/
public function remove()
{
SystemBase::mDelete();
}
}

View File

@ -1,132 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\service\AdminService;
use think\admin\service\ModuleService;
use think\admin\service\SystemService;
use think\admin\storage\AliossStorage;
use think\admin\storage\QiniuStorage;
use think\admin\storage\TxcosStorage;
/**
* 系统参数配置
* Class Config
* @package app\admin\controller
*/
class Config extends Controller
{
const themes = [
'default' => '默认色0',
'white' => '简约白0',
'red-1' => '玫瑰红1',
'blue-1' => '深空蓝1',
'green-1' => '小草绿1',
'black-1' => '经典黑1',
'red-2' => '玫瑰红2',
'blue-2' => '深空蓝2',
'green-2' => '小草绿2',
'black-2' => '经典黑2',
];
/**
* 系统参数配置
* @auth true
* @menu true
*/
public function index()
{
$this->title = '系统参数配置';
$this->super = AdminService::isSuper();
$this->version = ModuleService::getVersion();
$this->fetch();
}
/**
* 修改系统参数
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function system()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->title = '修改系统参数';
$this->themes = static::themes;
$this->fetch();
} else {
$post = $this->request->post();
// 修改网站后台入口路径
if (!empty($post['xpath'])) {
if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $post['xpath'])) {
$this->error('后台入口名称需要是由英文字母开头!');
}
if ($post['xpath'] !== 'admin' && file_exists($this->app->getBasePath() . $post['xpath'])) {
$this->error("后台入口名称{$post['xpath']}已经存在应用!");
}
SystemService::setRuntime(null, [$post['xpath'] => 'admin']);
}
// 修改网站 ICON 图标,替换 public/favicon.ico
if (preg_match('#^https?://#', $icon = $post['site_icon'] ?? '')) try {
SystemService::setFavicon($icon);
} catch (\Exception $exception) {
trace_file($exception);
}
// 数据数据到系统配置表
foreach ($post as $k => $v) sysconf($k, $v);
sysoplog('系统配置管理', "修改系统参数成功");
$this->success('修改系统参数成功!', admuri('admin/config/index'));
}
}
/**
* 修改文件存储
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function storage()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->type = input('type', 'local');
if ($this->type === 'alioss') {
$this->points = AliossStorage::region();
} elseif ($this->type === 'qiniu') {
$this->points = QiniuStorage::region();
} elseif ($this->type === 'txcos') {
$this->points = TxcosStorage::region();
}
$this->fetch("storage-{$this->type}");
} else {
$post = $this->request->post();
if (!empty($post['storage']['allow_exts'])) {
$deny = ['sh', 'asp', 'bat', 'cmd', 'exe', 'php'];
$exts = array_unique(str2arr(strtolower($post['storage']['allow_exts'])));
if (count(array_intersect($deny, $exts)) > 0) $this->error('禁止上传可执行的文件!');
$post['storage']['allow_exts'] = join(',', $exts);
}
foreach ($post as $name => $value) sysconf($name, $value);
sysoplog('系统配置管理', "修改系统存储参数");
$this->success('修改文件存储成功!');
}
}
}

View File

@ -1,88 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemFile;
use think\admin\service\AdminService;
use think\admin\Storage;
/**
* 系统文件管理
* Class File
* @package app\admin\controller
*/
class File extends Controller
{
/**
* 系统文件管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->types = Storage::types();
SystemFile::mQuery()->layTable(function () {
$this->title = '系统文件管理';
$this->xexts = SystemFile::mk()->distinct()->column('xext');
}, function (QueryHelper $query) {
$query->like('name,hash,xext')->equal('type')->dateBetween('create_at');
$query->where(['issafe' => 0, 'status' => 2, 'uuid' => AdminService::getUserId()]);
});
}
/**
* 数据列表处理
* @param array $data
* @return void
*/
protected function _page_filter(array &$data)
{
foreach ($data as &$vo) {
$vo['ctype'] = $this->types[$vo['type']] ?? $vo['type'];
}
}
/**
* 删除系统文件
* @auth true
* @return void
*/
public function remove()
{
SystemFile::mDelete();
}
/**
* 清理重复文件
* @auth true
* @return void
*/
public function distinct()
{
$map = ['uuid' => AdminService::getUserId()];
$db1 = SystemFile::mk()->fieldRaw('max(id) id')->where($map)->group('type,xkey');
$db2 = $this->app->db->table($db1->buildSql())->alias('dt')->field('id');
SystemFile::mk()->whereRaw("id not in {$db2->buildSql()}")->delete();
SystemFile::mk()->where($map)->where(['status' => 1])->delete();
$this->success('清理重复文件成功!');
}
}

View File

@ -1,155 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\admin\service\MenuService;
/**
* 后台界面入口
* Class Index
* @package app\admin\controller
*/
class Index extends Controller
{
/**
* 显示后台首页
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
/*! 根据运行模式刷新权限 */
AdminService::apply($this->app->isDebug());
/*! 读取当前用户权限菜单树 */
$this->menus = MenuService::getTree();
/*! 判断当前用户的登录状态 */
$this->login = AdminService::isLogin();
/*! 菜单为空且未登录跳转到登录页 */
if (empty($this->menus) && empty($this->login)) {
$this->redirect(sysuri('admin/login/index'));
} else {
$this->title = '系统管理后台';
$this->super = AdminService::isSuper();
$this->theme = AdminService::getUserTheme();
$this->fetch();
}
}
/**
* 后台主题切换
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function theme()
{
if ($this->request->isGet()) {
$this->theme = AdminService::getUserTheme();
$this->themes = Config::themes;
$this->fetch();
} else {
$data = $this->_vali(['site_theme.require' => '主题名称不能为空!']);
if (AdminService::setUserTheme($data['site_theme'])) {
$this->success('主题配置保存成功!');
} else {
$this->error('主题配置保存失败!');
}
}
}
/**
* 修改用户资料
* @login true
* @param mixed $id 用户ID
*/
public function info($id = 0)
{
$this->_applyFormToken();
if (AdminService::getUserId() === intval($id)) {
SystemUser::mForm('admin@user/form', 'id', [], ['id' => $id]);
} else {
$this->error('只能修改自己的资料!');
}
}
/**
* 资料修改表单处理
* @param array $data
*/
protected function _info_form_filter(array &$data)
{
if ($this->request->isPost()) {
unset($data['username'], $data['authorize']);
}
}
/**
* 资料修改结果处理
* @param bool $status
*/
protected function _info_form_result(bool $status)
{
if ($status) {
$this->success('用户资料修改成功!', 'javascript:location.reload()');
}
}
/**
* 修改当前用户密码
* @login true
* @param mixed $id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function pass($id = 0)
{
$this->_applyFormToken();
if (AdminService::getUserId() !== intval($id)) {
$this->error('只能修改当前用户的密码!');
}
if ($this->app->request->isGet()) {
$this->verify = true;
SystemUser::mForm('admin@user/pass', 'id', [], ['id' => $id]);
} else {
$data = $this->_vali([
'password.require' => '登录密码不能为空!',
'repassword.require' => '重复密码不能为空!',
'oldpassword.require' => '旧的密码不能为空!',
'password.confirm:repassword' => '两次输入的密码不一致!',
]);
$user = SystemUser::mk()->find($id);
if (empty($user)) $this->error('用户不存在!');
if (md5($data['oldpassword']) !== $user['password']) {
$this->error('旧密码验证失败,请重新输入!');
}
if ($user->save(['password' => md5($data['password'])])) {
sysoplog('系统用户管理', "修改用户[{$user['id']}]密码成功");
$this->success('密码修改成功,下次请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
}

View File

@ -1,132 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\admin\service\CaptchaService;
use think\admin\service\SystemService;
/**
* 用户登录管理
* Class Login
* @package app\admin\controller
*/
class Login extends Controller
{
/**
* 后台登录入口
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
if ($this->app->request->isGet()) {
if (AdminService::isLogin()) {
$this->redirect(sysuri('admin/index/index'));
} else {
// 当前运行模式
$this->developMode = SystemService::checkRunMode();
// 后台背景处理
$images = str2arr(sysconf('login_image') ?: '', '|') ?: [
SystemService::uri('/static/theme/img/login/bg1.jpg'), SystemService::uri('/static/theme/img/login/bg2.jpg'),
];
$this->loginStyle = sprintf('style="background-image:url(%s)" data-bg-transition="%s"', $images[0], join(',', $images));
// 登录验证令牌
$this->captchaType = 'LoginCaptcha';
$this->captchaToken = CodeExtend::uniqidDate(18);
if (!$this->app->session->get('LoginInputSessionError')) {
$this->app->session->set($this->captchaType, $this->captchaToken);
}
// 更新后台域名
if ($this->request->domain(true) !== sysconf('base.site_host')) {
sysconf('base.site_host', $this->request->domain(true));
}
// 加载登录模板
$this->title = '系统登录';
$this->fetch();
}
} else {
$data = $this->_vali([
'username.require' => '登录账号不能为空!',
'username.min:4' => '登录账号不能少于4位字符!',
'password.require' => '登录密码不能为空!',
'password.min:4' => '登录密码不能少于4位字符!',
'verify.require' => '图形验证码不能为空!',
'uniqid.require' => '图形验证标识不能为空!',
]);
if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
$this->error('图形验证码验证失败,请重新输入!');
}
/*! 用户信息验证 */
$map = ['username' => $data['username'], 'is_deleted' => 0];
$user = SystemUser::mk()->where($map)->findOrEmpty();
if ($user->isEmpty()) {
$this->app->session->set('LoginInputSessionError', true);
$this->error('登录账号或密码错误,请重新输入!');
}
if (empty($user['status'])) {
$this->app->session->set('LoginInputSessionError', true);
$this->error('账号已经被禁用,请联系管理员!');
}
if (md5("{$user['password']}{$data['uniqid']}") !== $data['password']) {
$this->app->session->set('LoginInputSessionError', true);
$this->error('登录账号或密码错误,请重新输入!');
}
$this->app->session->set('user', $user->toArray());
$this->app->session->delete('LoginInputSessionError');
$user->inc('login_num')->update([
'login_at' => date('Y-m-d H:i:s'),
'login_ip' => $this->app->request->ip(),
]);
sysoplog('系统用户登录', '登录系统后台成功');
$this->success('登录成功', sysuri('admin/index/index'));
}
}
/**
* 生成验证码
*/
public function captcha()
{
$input = $this->_vali([
'type.require' => '验证码类型不能为空!',
'token.require' => '验证码标识不能为空!',
]);
$image = CaptchaService::instance()->initialize();
$captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
if ($this->app->session->get($input['type']) === $input['token']) {
$captcha['code'] = $image->getCode();
$this->app->session->delete($input['type']);
}
$this->success('生成验证码成功', $captcha);
}
/**
* 退出登录
*/
public function out()
{
$this->app->session->clear();
$this->app->session->destroy();
$this->success('退出登录成功!', sysuri('admin/login/index'));
}
}

View File

@ -1,147 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\extend\DataExtend;
use think\admin\model\SystemMenu;
use think\admin\service\AdminService;
use think\admin\service\MenuService;
use think\admin\service\NodeService;
/**
* 系统菜单管理
* Class Menu
* @package app\admin\controller
*/
class Menu extends Controller
{
/**
* 系统菜单管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '系统菜单管理';
$this->type = input('get.type', 'index');
SystemMenu::mQuery()->layTable();
}
/**
* 列表数据处理
* @param array $data
*/
protected function _index_page_filter(array &$data)
{
$data = DataExtend::arr2tree($data);
// 回收站过滤有效菜单
if ($this->type === 'recycle') foreach ($data as $k1 => &$p1) {
if (!empty($p1['sub'])) foreach ($p1['sub'] as $k2 => &$p2) {
if (!empty($p2['sub'])) foreach ($p2['sub'] as $k3 => $p3) {
if ($p3['status'] > 0) unset($p2['sub'][$k3]);
}
if (empty($p2['sub']) && ($p2['url'] === '#' or $p2['status'] > 0)) unset($p1['sub'][$k2]);
}
if (empty($p1['sub']) && ($p1['url'] === '#' or $p1['status'] > 0)) unset($data[$k1]);
}
// 菜单数据树数据变平化
$data = DataExtend::arr2table($data);
foreach ($data as &$vo) {
if ($vo['url'] !== '#' && !preg_match('/^(https?:)?(\/\/|\\\\)/i', $vo['url'])) {
$vo['url'] = trim(url($vo['url']) . ($vo['params'] ? "?{$vo['params']}" : ''), '\\/');
}
}
}
/**
* 添加系统菜单
* @auth true
*/
public function add()
{
$this->_applyFormToken();
SystemMenu::mForm('form');
}
/**
* 编辑系统菜单
* @auth true
*/
public function edit()
{
$this->_applyFormToken();
SystemMenu::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
* @throws \ReflectionException
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isGet()) {
/* 清理权限节点 */
if ($isDebug = $this->app->isDebug()) {
AdminService::clearCache();
}
/* 读取系统功能节点 */
$this->auths = [];
$this->nodes = MenuService::getList($isDebug);
foreach (NodeService::getMethods($isDebug) as $node => $item) {
if ($item['isauth'] && substr_count($node, '/') >= 2) {
$this->auths[] = ['node' => $node, 'title' => $item['title']];
}
}
/* 选择自己上级菜单 */
$vo['pid'] = $vo['pid'] ?? input('pid', '0');
/* 列出可选上级菜单 */
$menus = SystemMenu::mk()->order('sort desc,id asc')->column('id,pid,icon,url,node,title,params', 'id');
$this->menus = DataExtend::arr2table(array_merge($menus, [['id' => '0', 'pid' => '-1', 'url' => '#', 'title' => '顶部菜单']]));
if (isset($vo['id'])) foreach ($this->menus as $menu) if ($menu['id'] === $vo['id']) $vo = $menu;
foreach ($this->menus as $key => $menu) if ($menu['spt'] >= 3 || $menu['url'] !== '#') unset($this->menus[$key]);
if (isset($vo['spt']) && isset($vo['spc']) && in_array($vo['spt'], [1, 2]) && $vo['spc'] > 0) {
foreach ($this->menus as $key => $menu) if ($vo['spt'] <= $menu['spt']) unset($this->menus[$key]);
}
}
}
/**
* 修改菜单状态
* @auth true
*/
public function state()
{
SystemMenu::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统菜单
* @auth true
*/
public function remove()
{
SystemMenu::mDelete();
}
}

View File

@ -1,74 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\service\ModuleService;
/**
* 系统模块管理
* Class Module
* @package app\admin\controller
*/
class Module extends Controller
{
/**
* 系统模块管理
* @auth true
* @menu true
*/
public function index()
{
$this->title = '系统模块管理';
$this->modules = ModuleService::change();
$this->fetch();
}
/**
* 安装更新模块
* @auth true
*/
public function install()
{
$data = $this->_vali(['name.require' => '模块名称不能为空!']);
[$state, $message] = ModuleService::install($data['name']);
$state ? $this->success($message) : $this->error($message);
}
/**
* 查看模块更新
* @auth true
*/
public function change()
{
$data = $this->_vali(['name.require' => '模块名称不能为空!']);
$online = ModuleService::online();
$locals = ModuleService::getModules();
if (isset($online[$data['name']])) {
$this->module = $online[$data['name']];
$this->current = $locals[$data['name']] ?? [];
$pattern = "|^(\d{4})\.(\d{2})\.(\d{2})\.(\d+)$|";
$this->module['change'] = array_reverse($this->module['change']);
foreach ($this->module['change'] as $version => &$change) {
$change = ['content' => $change, 'version' => preg_replace($pattern, '$1年$2月$3日 更新', $version)];
}
$this->fetch();
} else {
$this->error('未查询到模块更新记录!');
}
}
}

View File

@ -1,93 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use Exception;
use Ip2Region;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemOplog;
use think\exception\HttpResponseException;
/**
* 系统日志管理
* Class Oplog
* @package app\admin\controller
*/
class Oplog extends Controller
{
/**
* 系统日志管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemOplog::mQuery()->layTable(function () {
$this->title = '系统日志管理';
$columns = SystemOplog::mk()->column('action,username', 'id');
$this->users = array_unique(array_column($columns, 'username'));
$this->actions = array_unique(array_column($columns, 'action'));
}, function (QueryHelper $query) {
$query->dateBetween('create_at')->equal('username,action')->like('content,geoip,node');
});
}
/**
* 列表数据处理
* @auth true
* @param array $data
* @throws \Exception
*/
protected function _index_page_filter(array &$data)
{
$region = new Ip2Region();
foreach ($data as &$vo) {
$isp = $region->btreeSearch($vo['geoip']);
$vo['geoisp'] = str_replace(['内网IP', '0', '|'], '', $isp['region'] ?? '') ?: '-';
}
}
/**
* 清理系统日志
* @auth true
*/
public function clear()
{
try {
SystemOplog::mQuery()->empty();
sysoplog('系统运维管理', '成功清理所有日志');
$this->success('日志清理成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error("日志清理失败,{$exception->getMessage()}");
}
}
/**
* 删除系统日志
* @auth true
*/
public function remove()
{
SystemOplog::mDelete();
}
}

View File

@ -1,115 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use Exception;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemQueue;
use think\admin\service\AdminService;
use think\admin\service\ProcessService;
use think\admin\service\QueueService;
use think\exception\HttpResponseException;
/**
* 系统任务管理
* Class Queue
* @package app\admin\controller
*/
class Queue extends Controller
{
/**
* 系统任务管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
SystemQueue::mQuery()->layTable(function () {
$this->title = '系统任务管理';
$this->iswin = ProcessService::iswin();
if ($this->super = AdminService::isSuper()) {
$this->command = ProcessService::think('xadmin:queue start');
if (!$this->iswin && !empty($_SERVER['USER'])) {
$this->command = "sudo -u {$_SERVER['USER']} {$this->command}";
}
}
}, function (QueryHelper $query) {
$query->equal('status')->like('code|title#title,command');
$query->timeBetween('enter_time,exec_time')->dateBetween('create_at');
});
}
/**
* 分页数据回调处理
* @param array $data
* @param array $result
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _index_page_filter(array $data, array &$result)
{
$result['extra'] = ['dos' => 0, 'pre' => 0, 'oks' => 0, 'ers' => 0];
SystemQueue::mk()->field('status,count(1) count')->group('status')->select()->map(function ($item) use (&$result) {
if ($item['status'] === 1) $result['extra']['pre'] = $item['count'];
if ($item['status'] === 2) $result['extra']['dos'] = $item['count'];
if ($item['status'] === 3) $result['extra']['oks'] = $item['count'];
if ($item['status'] === 4) $result['extra']['ers'] = $item['count'];
});
}
/**
* 重启系统任务
* @auth true
*/
public function redo()
{
try {
$data = $this->_vali(['code.require' => '任务编号不能为空!']);
$queue = QueueService::instance()->initialize($data['code'])->reset();
$queue->progress(1, '>>> 任务重置成功 <<<', 0.00);
$this->success('任务重置成功!', $queue->code);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 清理运行数据
* @auth true
*/
public function clean()
{
$this->_queue('定时清理系统运行数据', "xadmin:queue clean", 0, [], 0, 3600);
}
/**
* 删除系统任务
* @auth true
*/
public function remove()
{
SystemQueue::mDelete();
}
}

View File

@ -1,180 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemAuth;
use think\admin\model\SystemBase;
use think\admin\model\SystemUser;
use think\admin\service\AdminService;
use think\model\Relation;
/**
* 系统用户管理
* Class User
* @package app\admin\controller
*/
class User extends Controller
{
/**
* 系统用户管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = input('get.type', 'index');
// 创建快捷查询工具
SystemUser::mQuery()->layTable(function () {
$this->title = '系统用户管理';
$this->bases = SystemBase::items('身份权限');
}, function (QueryHelper $query) {
// 加载对应数据列表
$query->where(['is_deleted' => 0, 'status' => intval($this->type === 'index')]);
// 关联用户身份资料
$query->with(['userinfo' => function (Relation $relation) {
$relation->field('code,name,content');
}]);
// 数据列表搜索过滤
$query->equal('status,usertype')->dateBetween('login_at,create_at');
$query->like('username|nickname#username,contact_phone#phone,contact_mail#mail');
});
}
/**
* 添加系统用户
* @auth true
*/
public function add()
{
SystemUser::mForm('form');
}
/**
* 编辑系统用户
* @auth true
*/
public function edit()
{
SystemUser::mForm('form');
}
/**
* 修改用户密码
* @auth true
*/
public function pass()
{
$this->_applyFormToken();
if ($this->request->isGet()) {
$this->verify = false;
SystemUser::mForm('pass');
} else {
$data = $this->_vali([
'id.require' => '用户ID不能为空',
'password.require' => '登录密码不能为空!',
'repassword.require' => '重复密码不能为空!',
'repassword.confirm:password' => '两次输入的密码不一致!',
]);
$user = SystemUser::mk()->findOrEmpty($data['id']);
if ($user->isExists() && $user->save(['password' => md5($data['password'])])) {
sysoplog('系统用户管理', "修改用户[{$data['id']}]密码成功");
$this->success('密码修改成功,请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if ($this->request->isPost()) {
// 账号权限绑定处理
$data['authorize'] = arr2str($data['authorize'] ?? []);
if (isset($data['id']) && $data['id'] > 0) {
unset($data['username']);
} else {
// 检查账号是否重复
if (empty($data['username'])) {
$this->error('登录账号不能为空!');
}
$map = ['username' => $data['username'], 'is_deleted' => 0];
if (SystemUser::mk()->where($map)->count() > 0) {
$this->error("账号已经存在,请使用其它账号!");
}
// 新添加的用户密码与账号相同
$data['password'] = md5($data['username']);
}
} else {
// 权限绑定处理
$data['authorize'] = str2arr($data['authorize'] ?? '');
// 用户身份数据
$this->bases = SystemBase::items('身份权限');
// 用户权限管理
$this->superName = AdminService::getSuperName();
$this->authorizes = SystemAuth::items();
}
}
/**
* 修改用户状态
* @auth true
*/
public function state()
{
$this->_checkInput();
SystemUser::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统用户
* @auth true
*/
public function remove()
{
$this->_checkInput();
SystemUser::mDelete();
}
/**
* 检查输入变量
*/
private function _checkInput()
{
if (in_array('10000', str2arr(input('id', '')))) {
$this->error('系统超级账号禁止删除!');
}
}
}

View File

@ -1,73 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\service\AdminService;
/**
* 通用插件管理
* Class Plugs
* @package app\admin\controller\api
*/
class Plugs extends Controller
{
/**
* 图标选择器
* @login true
*/
public function icon()
{
$this->title = '图标选择器';
$this->field = $this->app->request->get('field', 'icon');
$this->fetch(realpath(__DIR__ . '/../../view/api/icon.html'));
}
/**
* 前端脚本变量
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function script(): \think\Response
{
$taDebug = $this->app->isDebug() ? 'true' : 'false';
$taAdmin = sysuri('admin/index/index', [], false);
$taEditor = sysconf('base.editor') ?: 'ckeditor4';
return response(join("\n", [
"window.taDebug = {$taDebug};",
"window.taAdmin = '{$taAdmin}';",
"window.taEditor = '{$taEditor}';",
]))->contentType('application/x-javascript');
}
/**
* 优化数据库
* @login true
*/
public function optimize()
{
if (AdminService::isSuper()) {
sysoplog('系统运维管理', '创建数据库优化任务');
$this->_queue('优化数据库所有数据表', 'xadmin:database optimize');
} else {
$this->error('只有超级管理员才能操作!');
}
}
}

View File

@ -1,112 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use Exception;
use think\admin\Controller;
use think\admin\service\AdminService;
use think\admin\service\QueueService;
use think\exception\HttpResponseException;
/**
* 后台任务通用接口
* Class Queue
* @package app\admin\controller\api
*/
class Queue extends Controller
{
/**
* 任务进度查询
* @login true
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function progress()
{
$input = $this->_vali(['code.require' => '任务编号不能为空!']);
$queue = QueueService::instance()->initialize($input['code']);
$this->success('获取任务进度成功!', $queue->progress());
}
/**
* WIN停止监听进程
* @login true
*/
public function stop()
{
try {
$message = $this->app->console->call('xadmin:queue', ['stop'])->fetch();
if (stripos($message, 'sent end signal to process')) {
sysoplog('系统运维管理', '尝试停止后台服务主进程');
$this->success('停止后台服务主进程成功!');
} elseif (stripos($message, 'processes to stop')) {
$this->success('没有找到需要停止的进程!');
} else {
$this->error(nl2br($message));
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* WIN创建监听进程
* @login true
*/
public function start()
{
try {
$message = $this->app->console->call('xadmin:queue', ['start'])->fetch();
if (stripos($message, 'daemons started successfully for pid')) {
sysoplog('系统运维管理', '尝试启动后台服务主进程');
$this->success('后台服务主进程启动成功!');
} elseif (stripos($message, 'daemons already exist for pid')) {
$this->success('后台服务主进程已经存在!');
} else {
$this->error(nl2br($message));
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 检查任务状态
* @login true
*/
public function status()
{
if (AdminService::isSuper()) try {
$message = $this->app->console->call('xadmin:queue', ['status'])->fetch();
if (preg_match('/process.*?\d+.*?running/', $message)) {
echo "<span class='color-green pointer' data-tips-text='{$message}'>已启动</span>";
} else {
echo "<span class='color-red pointer' data-tips-text='{$message}'>未启动</span>";
}
} catch (Exception $exception) {
echo "<span class='color-red pointer' data-tips-text='{$exception->getMessage()}'>异 常</span>";
} else {
echo "<span class='color-red pointer' data-tips-text='只有超级管理员才能操作!'>无权限</span>";
}
}
}

View File

@ -1,139 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\model\SystemConfig;
use think\admin\service\AdminService;
use think\admin\service\SystemService;
use think\exception\HttpResponseException;
/**
* 系统运行控制管理
* Class System
* @package app\admin\controller\api
*/
class System extends Controller
{
/**
* 网站压缩发布
* @login true
*/
public function push()
{
if (AdminService::isSuper()) try {
AdminService::clearCache();
SystemService::pushRuntime();
sysoplog('系统运维管理', '刷新创建路由缓存');
$this->success('网站缓存加速成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 清理运行缓存
* @login true
*/
public function clear()
{
if (AdminService::isSuper()) try {
AdminService::clearCache();
SystemService::clearRuntime();
sysoplog('系统运维管理', '清理网站日志缓存');
$this->success('清空日志缓存成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 当前运行模式
* @login true
*/
public function debug()
{
if (AdminService::isSuper()) if (input('state')) {
SystemService::setRuntime('product');
sysoplog('系统运维管理', '开发模式切换为生产模式');
$this->success('已切换为生产模式!', 'javascript:location.reload()');
} else {
SystemService::setRuntime('debug');
sysoplog('系统运维管理', '生产模式切换为开发模式');
$this->success('已切换为开发模式!', 'javascript:location.reload()');
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 修改富文本编辑器
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function editor()
{
if (AdminService::isSuper()) {
$editor = input('editor', 'auto');
sysconf('base.editor', $editor);
sysoplog('系统运维管理', "切换编辑器为{$editor}");
$this->success('已切换后台编辑器!', 'javascript:location.reload()');
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 清理系统配置
* @login true
*/
public function config()
{
if (AdminService::isSuper()) try {
[$tmpdata, $newdata] = [[], []];
foreach (SystemConfig::mk()->order('type,name asc')->cursor() as $item) {
$tmpdata[$item['type']][$item['name']] = $item['value'];
}
foreach ($tmpdata as $type => $items) foreach ($items as $name => $value) {
$newdata[] = ['type' => $type, 'name' => $name, 'value' => $value];
}
$this->app->db->transaction(function () use ($newdata) {
SystemConfig::mQuery()->empty()->insertAll($newdata);
});
$this->app->cache->delete('SystemConfig');
sysoplog('系统运维管理', '清理系统配置参数');
$this->success('清理系统配置成功!', 'javascript:location.reload()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
} else {
$this->error('只有超级管理员才能操作!');
}
}
}

View File

@ -1,77 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\service\ModuleService;
use think\admin\service\SystemService;
/**
* 安装服务端支持
* Class Update
* @package app\admin\controller\api
*/
class Update extends Controller
{
/**
* 访问环境拦截
*/
protected function initialize()
{
if (!SystemService::checkRunMode()) {
$this->error('只允许访问本地或官方代码!');
}
}
/**
* 读取文件内容
*/
public function get()
{
$filename = decode(input('encode', '0'));
if (!ModuleService::checkAllowDownload($filename)) {
$this->error('下载的文件不在认证规则中!');
}
if (file_exists($realname = $this->app->getRootPath() . $filename)) {
$this->success('读取文件内容成功!', [
'content' => base64_encode(file_get_contents($realname)),
]);
} else {
$this->error('读取文件内容失败!');
}
}
/**
* 读取文件列表
*/
public function node()
{
$this->success('获取文件列表成功!', ModuleService::getChanges(
json_decode($this->request->post('rules', '[]', ''), true),
json_decode($this->request->post('ignore', '[]', ''), true)
));
}
/**
* 获取模块信息
*/
public function version()
{
$this->success('获取模块信息成功!', ModuleService::getModules());
}
}

View File

@ -1,326 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemFile;
use think\admin\service\AdminService;
use think\admin\Storage;
use think\admin\storage\AliossStorage;
use think\admin\storage\LocalStorage;
use think\admin\storage\QiniuStorage;
use think\admin\storage\TxcosStorage;
use think\admin\storage\UpyunStorage;
use think\exception\HttpResponseException;
use think\file\UploadedFile;
use think\Response;
/**
* 文件上传接口
* Class Upload
* @package app\admin\controller\api
*/
class Upload extends Controller
{
/**
* 文件上传脚本
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index(): Response
{
$data = ['exts' => []];
foreach (str2arr(sysconf('storage.allow_exts')) as $ext) {
$data['exts'][$ext] = Storage::mime($ext);
}
$template = realpath(__DIR__ . '/../../view/api/upload.js');
$data['exts'] = json_encode($data['exts'], JSON_UNESCAPED_UNICODE);
$data['nameType'] = sysconf('storage.name_type') ?: 'xmd5';
return view($template, $data)->contentType('application/x-javascript');
}
/**
* 文件上传检查
* @login true
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function state()
{
[$name, $safe] = [input('name'), $this->getSafe()];
$data = ['uptype' => $this->getType(), 'safe' => intval($safe), 'key' => input('key')];
$file = SystemFile::mk()->data($this->_vali([
'xkey.value' => $data['key'],
'type.value' => $this->getType(),
'uuid.value' => AdminService::getUserId(),
'name.require' => '名称不能为空!',
'hash.require' => '哈希不能为空!',
'xext.require' => '后缀不能为空!',
'size.require' => '大小不能为空!',
'mime.default' => '',
'status.value' => 1,
]));
if (empty($file['mime'])) $file['mime'] = Storage::mime($file['xext']);
$info = Storage::instance($data['uptype'])->info($data['key'], $safe, $name);
if (is_array($info) && isset($info['url']) && isset($info['key'])) {
$file->save(['xurl' => $info['url'], 'isfast' => 1, 'issafe' => $data['safe']]);
$extr = ['id' => $file->id ?? 0, 'url' => $info['url'], 'key' => $info['key']];
$this->success('文件已经上传', array_merge($data, $extr), 200);
} elseif ('local' === $data['uptype']) {
$data['url'] = LocalStorage::instance()->url($data['key'], $safe, $name);
$data['server'] = LocalStorage::instance()->upload();
} elseif ('qiniu' === $data['uptype']) {
$data['url'] = QiniuStorage::instance()->url($data['key'], $safe, $name);
$data['token'] = QiniuStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['server'] = QiniuStorage::instance()->upload();
} elseif ('alioss' === $data['uptype']) {
$token = AliossStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['url'] = $token['siteurl'];
$data['policy'] = $token['policy'];
$data['signature'] = $token['signature'];
$data['OSSAccessKeyId'] = $token['keyid'];
$data['server'] = AliossStorage::instance()->upload();
} elseif ('txcos' === $data['uptype']) {
$token = TxcosStorage::instance()->buildUploadToken($data['key'], 3600, $name);
$data['url'] = $token['siteurl'];
$data['q-ak'] = $token['q-ak'];
$data['policy'] = $token['policy'];
$data['q-key-time'] = $token['q-key-time'];
$data['q-signature'] = $token['q-signature'];
$data['q-sign-algorithm'] = $token['q-sign-algorithm'];
$data['server'] = TxcosStorage::instance()->upload();
} elseif ('upyun' === $data['uptype']) {
$token = UpyunStorage::instance()->buildUploadToken($data['key'], 3600, $name, input('size'), input('hash'));
$data['url'] = $token['siteurl'];
$data['policy'] = $token['policy'];
$data['authorization'] = $token['authorization'];
$data['server'] = UpyunStorage::instance()->upload();
}
$file->save(['xurl' => $data['url'], 'isfast' => 0, 'issafe' => $data['safe']]);
$this->success('获取上传授权参数', array_merge($data, ['id' => $file->id ?? 0]), 404);
}
/**
* 更新文件状态
* @login true
* @return void
*/
public function done()
{
$data = $this->_vali([
'id.require' => '编号不能为空!',
'hash.require' => '哈希不能为空!',
'uuid.value' => AdminService::getUserId(),
]);
$file = SystemFile::mk()->where($data)->findOrEmpty();
if ($file->isEmpty()) $this->error('文件不存在!');
if ($file->save(['status' => 2])) {
$this->success('更新成功!');
} else {
$this->error('更新失败!');
}
}
/**
* 文件选择器
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function image()
{
SystemFile::mQuery()->layTable(function () {
$this->title = '文件选择器';
}, function (QueryHelper $query) {
$query->where(['status' => 2, 'issafe' => 0, 'uuid' => AdminService::getUserId()]);
$query->like('name,hash')->in('xext#type')->dateBetween('create_at')->order('id desc');
});
}
/**
* 视频选择器
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function video()
{
SystemFile::mQuery()->layTable(function () {
$this->title = '文件选择器';
}, function (QueryHelper $query) {
$query->like('name,hash')->dateBetween('create_at')->order('id desc');
$query->where(['status' => 2, 'issafe' => 0, 'uuid' => AdminService::getUserId()]);
});
}
/**
* 文档选择器
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function document()
{
SystemFile::mQuery()->layTable(function () {
$this->title = '文件选择器';
}, function (QueryHelper $query) {
$query->like('name,hash')->dateBetween('create_at')->order('id desc');
$query->where(['status' => 2, 'issafe' => 0, 'uuid' => AdminService::getUserId()]);
});
}
/**
* 文件上传入口
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function file()
{
if (!($file = $this->getFile())->isValid()) {
$this->error('文件上传异常,文件过大或未上传!');
}
$safeMode = $this->getSafe();
$extension = strtolower($file->getOriginalExtension());
$saveName = input('key') ?: Storage::name($file->getPathname(), $extension, '', 'md5_file');
// 检查文件名称是否合法
if (strpos($saveName, '../') !== false) {
$this->error('文件路径不能出现跳级操作!');
}
// 检查文件后缀是否被恶意修改
if (strtolower(pathinfo(parse_url($saveName, PHP_URL_PATH), PATHINFO_EXTENSION)) !== $extension) {
$this->error('文件后缀异常,请重新上传文件!');
}
// 屏蔽禁止上传指定后缀的文件
if (!in_array($extension, str2arr(sysconf('storage.allow_exts')))) {
$this->error('文件类型受限,请在后台配置规则!');
}
if (in_array($extension, ['sh', 'asp', 'bat', 'cmd', 'exe', 'php'])) {
$this->error('文件安全保护,禁止上传可执行文件!');
}
try {
if ($this->getType() === 'local') {
$local = LocalStorage::instance();
$distName = $local->path($saveName, $safeMode);
$file->move(dirname($distName), basename($distName));
$info = $local->info($saveName, $safeMode, $file->getOriginalName());
if (in_array($extension, ['jpg', 'gif', 'png', 'bmp', 'jpeg', 'wbmp'])) {
if ($this->imgNotSafe($distName) && $local->del($saveName)) {
$this->error('图片未通过安全检查!');
}
[$width, $height] = getimagesize($distName);
if (($width < 1 || $height < 1) && $local->del($saveName)) {
$this->error('读取图片的尺寸失败!');
}
}
} else {
$bina = file_get_contents($file->getPathname());
$info = Storage::instance($this->getType())->set($saveName, $bina, $safeMode, $file->getOriginalName());
}
if (isset($info['url'])) {
$this->success('文件上传成功!', ['url' => $safeMode ? $saveName : $info['url']]);
} else {
$this->error('文件处理失败,请稍候再试!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 获取文件上传类型
* @return boolean
*/
private function getSafe(): bool
{
return boolval(input('safe', '0'));
}
/**
* 获取文件上传方式
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getType(): string
{
$type = strtolower(input('uptype', ''));
if (in_array($type, ['local', 'qiniu', 'alioss', 'txcos', 'uptype'])) {
return $type;
} else {
return strtolower(sysconf('storage.type'));
}
}
/**
* 获取本地文件对象
* @return UploadedFile|void
*/
private function getFile(): UploadedFile
{
try {
$file = $this->request->file('file');
if ($file instanceof UploadedFile) {
return $file;
} else {
$this->error('未获取到上传的文件对象!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error(lang($exception->getMessage()));
}
}
/**
* 检查图片是否安全
* @param string $filename
* @return boolean
*/
private function imgNotSafe(string $filename): bool
{
$source = fopen($filename, 'rb');
if (($size = filesize($filename)) > 512) {
$hexs = bin2hex(fread($source, 512));
fseek($source, $size - 512);
$hexs .= bin2hex(fread($source, 512));
} else {
$hexs = bin2hex(fread($source, $size));
}
if (is_resource($source)) fclose($source);
$bins = hex2bin($hexs);
/* 匹配十六进制中的 <% ( ) %> 或 <? ( ) ?> 或 <script | /script> */
foreach (['<?php ', '<% ', '<script '] as $key) if (stripos($bins, $key) !== false) return true;
return preg_match("/(3c25.*?28.*?29.*?253e)|(3c3f.*?28.*?29.*?3f3e)|(3C534352495054)|(2F5343524950543E)|(3C736372697074)|(2F7363726970743E)/is", $hexs);
}
}

View File

@ -1,7 +0,0 @@
* 系统模块初始化成功
* 这次更新了许多内容哦
* 少量更新修复部分BUG
* 修正系统用户搜索
* 系统菜单支持外链
* 修复任意下载问题
* 优化模块管理机制

View File

@ -1,3 +0,0 @@
* 数据展示优化
* 后台UI升级到最新版本
* 后台文件上传机制优化

View File

@ -1,10 +0,0 @@
* 增加 .flex 及相关样式 class
* 升级 layui-2.7 测试版本并增加了 flex 样式
* 增加 .help-images 图片上传容器,支持单图或多图
* 增加 .help-checks 多项选择器容器,支持 raido,checkbox
* 修复 layui.form.checkbox 特殊情况下的异常
* 修改 ui 主布局的阴影生成方式,修改 NotSelect 使用
* 修改内容主容器(.think-page-body>.layui-body) 样式
* 其他细节调整见 _config.less 文件及 _layout.less 文件
* 修改系统任务管理界面,简化数据统计及状态检测数据展示
* 优化 admin.js 加载 loding 显示,首次加载等待成功后再显示界面

View File

@ -1,12 +0,0 @@
* 框架核心服务层静态化重构,增加后台皮肤样式选择与配置
* 升级 layui 版本到 2.7.4,引入 jszip 插件,引入图片压缩插件
* 重构文件上传机制,增加文件记录,增加进度 tips 提示,增加图片压缩
* 引入 ckeditor5 富文本编辑器,同时保存原 ckeditor4 版本,可后台切换
* 全局改写 layTable 动态数据表格,支持静态刷新,同时兼容原生 table 方式
* 增加 CORS 跨域规则配置,配置参数置放于 config/app.php需要更新 ThinkLibrary
* 修复 layui.table 导致基于 ThinkPHP 模板输出自动转义 XSS 过滤机制失效,需要更新 ThinkLibrary
* 修复在模板中使用 {:input(NAME)} 取值而产生的 XSS 问题,模板取值更换为 {$get.NAME|default=''}
* 修复 ckeditor4 配置文件,禁用所有标签的 on 事件,阻止 XSS 脚本注入,需要更新 ckeditor4/config.js
* 修复上传入口的后缀验证,读取真实文件后缀与配置对比,阻止不合法的文件上传并存储到本地服务器
* 修改 JsonRpc 接口异常处理机制,当服务端绑定 Exception 时,客户端将能收到 error 消息及异常数据
* 修改 location.hash 访问机制,禁止直接访问外部 URL 资源链接,防止外部 XSS 攻击读取本地缓存数据

View File

@ -1,51 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
return [
'name' => 'admin',
'vers' => '2022.03.06.01',
'user' => '广州楚才信息科技有限公司',
'link' => 'https://www.cuci.cc',
'desc' => '系统管理模块,提供系统配置及应用模块管理。',
'menu' => [
[
'name' => '应用管理',
'subs' => [],
],
[
'name' => '系统管理',
'subs' => [
[
'name' => '系统配置',
'subs' => [
['name' => '系统参数配置', 'icon' => 'layui-icon layui-icon-set', 'path' => 'admin/config/index'],
['name' => '系统任务管理', 'icon' => 'layui-icon layui-icon-log', 'path' => 'admin/queue/index'],
['name' => '系统日志管理', 'icon' => 'layui-icon layui-icon-tabs', 'path' => 'admin/oplog/index'],
['name' => '应用模块管理', 'icon' => 'layui-icon layui-icon-app', 'path' => 'admin/module/index'],
['name' => '数据字典管理', 'icon' => 'layui-icon layui-icon-read', 'path' => 'admin/base/index'],
],
],
[
'name' => '权限管理',
'subs' => [
['name' => '访问权限管理', 'icon' => 'layui-icon layui-icon-vercode', 'path' => 'admin/auth/index'],
['name' => '系统用户管理', 'icon' => 'layui-icon layui-icon-username', 'path' => 'admin/user/index'],
],
],
],
],
],
];

View File

@ -1,6 +0,0 @@
{
"name": "admin",
"author": "Anyon",
"version": "2022.07.11.01",
"content": "ThinkAdmin 系统基础模块"
}

View File

@ -1,59 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免费声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
use think\admin\Library;
use think\admin\service\SystemService;
/*! 非开发环境,清理限制文件 */
if (Library::$sapp->request->isGet() && !SystemService::checkRunMode()) {
@unlink(Library::$sapp->getBasePath() . 'admin/controller/api/Update.php');
@unlink(Library::$sapp->getBasePath() . 'admin/route/demo.php');
@rmdir(Library::$sapp->getBasePath() . 'admin/route');
}
/*! 演示环境禁止操作路由绑定 */
if (SystemService::checkRunMode('demo')) {
Library::$sapp->route->post('index/pass', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改用户密码!']);
});
Library::$sapp->route->post('config/system', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改系统配置!']);
});
Library::$sapp->route->post('config/storage', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改系统配置!']);
});
Library::$sapp->route->post('menu', function () {
return json(['code' => 0, 'info' => '演示环境禁止给菜单排序!']);
});
Library::$sapp->route->post('menu/index', function () {
return json(['code' => 0, 'info' => '演示环境禁止给菜单排序!']);
});
Library::$sapp->route->post('menu/add', function () {
return json(['code' => 0, 'info' => '演示环境禁止添加菜单!']);
});
Library::$sapp->route->post('menu/edit', function () {
return json(['code' => 0, 'info' => '演示环境禁止编辑菜单!']);
});
Library::$sapp->route->post('menu/state', function () {
return json(['code' => 0, 'info' => '演示环境禁止禁用菜单!']);
});
Library::$sapp->route->post('menu/remove', function () {
return json(['code' => 0, 'info' => '演示环境禁止删除菜单!']);
});
Library::$sapp->route->post('user/pass', function () {
return json(['code' => 0, 'info' => '演示环境禁止修改用户密码!']);
});
}

File diff suppressed because it is too large Load Diff

View File

@ -1,307 +0,0 @@
define(['md5', 'notify'], function (SparkMD5, Notify, allowMime) {
allowMime = JSON.parse('{$exts|raw}');
function UploadAdapter(elem, done) {
return new (function (elem, done, that) {
/*! 初始化变量 */
that = this;
this.option = {elem: $(elem), exts: [], mimes: []};
this.option.size = this.option.elem.data('size') || 0;
this.option.safe = this.option.elem.data('safe') ? 1 : 0;
this.option.hide = this.option.elem.data('hload') ? 1 : 0;
this.option.mult = this.option.elem.data('multiple') > 0;
this.option.path = (this.option.elem.data('path') || '').replace(/\W/g, '');
this.option.type = this.option.safe ? 'local' : this.option.elem.attr('data-uptype') || '';
this.option.quality = parseFloat(this.option.elem.data('quality') || '1.0');
this.option.maxWidth = parseInt(this.option.elem.data('max-width') || '0');
this.option.maxHeight = parseInt(this.option.elem.data('max-height') || '0');
this.option.cutWidth = parseInt(this.option.elem.data('cut-width') || '0');
this.option.cutHeight = parseInt(this.option.elem.data('cut-height') || '0');
/*! 查找表单元素, 如果没有找到将不会自动写值 */
if (!this.option.elem.data('input') && this.option.elem.data('field')) {
this.$input = $('input[name="' + this.option.elem.data('field') + '"]:not([type=file])');
this.option.elem.data('input', this.$input.size() > 0 ? this.$input.get(0) : null);
}
/*! 文件选择筛选,使用 MIME 规则过滤文件列表 */
$((this.option.elem.data('type') || '').split(',')).map(function (i, e) {
if (allowMime[e]) that.option.exts.push(e), that.option.mimes.push(allowMime[e]);
});
/*! 初始化上传组件 */
this.adapter = new Adapter(this.option, layui.upload.render({
url: '{:url("admin/api.upload/file")}', auto: false, elem: elem, accept: 'file', multiple: this.option.mult, exts: this.option.exts.join('|'), acceptMime: this.option.mimes.join(','), choose: function (obj) {
obj.items = [], obj.files = obj.pushFile();
layui.each(obj.files, function (idx, file) {
obj.items.push(file);
file.path = that.option.path;
file.quality = that.option.quality;
file.maxWidth = that.option.maxWidth;
file.maxHeight = that.option.maxHeight;
file.cutWidth = that.option.cutWidth;
file.cutHeight = that.option.cutHeight;
});
that.adapter.event('upload.choose', obj.items);
that.adapter.upload(obj.items, done);
layui.each(obj.files, function (idx) {
delete obj.files[idx];
});
}
}));
})(elem, done)
}
// 创建对象
UploadAdapter.adapter = window.AdminUploadAdapter = Adapter;
// 上传文件
function Adapter(option, uploader) {
this.uploader = uploader, this.config = function (option) {
return (this.option = Object.assign({}, this.option || {}, option || {})), this;
}, this.init = function (option) {
this.uploader && this.uploader.config.elem.next().val('');
this.files = {}, this.loader = 0, this.count = {total: 0, error: 0, success: 0};
return this.config(option).config({safe: this.option.safe || 0, type: this.option.type || ''});
}, this.init(option);
}
// 文件推送
Adapter.prototype.upload = function (files, done) {
var that = this.init();
layui.each(files, function (index, file) {
that.count.total++, file.index = index, that.files[index] = file;
if (that.option.size && file.size > that.option.size) {
that.event('upload.error', {file: file}, file, '大小超限');
} else if (!that.option.hide) {
file.notify = new NotifyExtend(file);
}
}), layui.each(files, function (index, file) {
// 禁传异常状态文件
if (typeof file.xstate === 'number' && file.xstate === -1) return;
// 图片限宽限高压缩
if (/^image\//.test(file.type) && (file.maxWidth + file.maxHeight + file.cutWidth + file.cutHeight > 0 || file.quality !== 1)) {
require(['compressor'], function (Compressor) {
new Compressor(file, {
quality: file.quality, resize: 'cover', width: file.cutWidth || 0, height: file.cutHeight || 0, maxWidth: file.maxWidth, maxHeight: file.maxHeight, success(blob) {
blob.index = file.index, blob.notify = file.notify, blob.path = file.path, files[index] = blob;
that.hash(files[index]).then(function (file) {
that.event('upload.hash', file).request(file, done);
});
}, error: function () {
that.event('upload.error', {file: file}, file, '压缩失败');
}
});
});
} else {
that.hash(file).then(function (file) {
that.event('upload.hash', file).request(file, done);
});
}
});
};
// 文件上传
Adapter.prototype.request = function (file, done) {
var that = this, data = {key: file.xkey, safe: that.option.safe, uptype: that.option.type};
data.size = file.size, data.name = file.name, data.hash = file.xmd5, data.mime = file.type, data.xext = file.xext;
jQuery.ajax("{:url('admin/api.upload/state')}", {
data: data, method: 'post', success: function (ret) {
file.id = ret.data.id || 0, file.xurl = ret.data.url;
file.xsafe = ret.data.safe, file.xpath = ret.data.key, file.xtype = ret.data.uptype;
if (parseInt(ret.code) === 404) {
var uploader = {};
uploader.url = ret.data.server;
uploader.form = new FormData();
uploader.form.append('key', ret.data.key);
uploader.form.append('safe', ret.data.safe);
uploader.form.append('uptype', ret.data.uptype);
if (ret.data.uptype === 'qiniu') {
uploader.form.append('token', ret.data.token);
} else if (ret.data.uptype === 'alioss') {
uploader.form.append('policy', ret.data['policy']);
uploader.form.append('signature', ret.data['signature']);
uploader.form.append('OSSAccessKeyId', ret.data['OSSAccessKeyId']);
uploader.form.append('success_action_status', '200');
uploader.form.append('Content-Disposition', 'inline;filename=' + encodeURIComponent(file.name));
} else if (ret.data.uptype === 'txcos') {
uploader.form.append('q-ak', ret.data['q-ak']);
uploader.form.append('policy', ret.data['policy']);
uploader.form.append('q-key-time', ret.data['q-key-time']);
uploader.form.append('q-signature', ret.data['q-signature']);
uploader.form.append('q-sign-algorithm', ret.data['q-sign-algorithm']);
uploader.form.append('success_action_status', '200');
uploader.form.append('Content-Disposition', 'inline;filename=' + encodeURIComponent(file.name));
} else if (ret.data.uptype === 'upyun') {
uploader.form.delete('key');
uploader.form.delete('safe');
uploader.form.delete('uptype');
uploader.form.append('save-key', ret.data['key']);
uploader.form.append('policy', ret.data['policy']);
uploader.form.append('authorization', ret.data['authorization']);
uploader.form.append('Content-Disposition', 'inline;filename=' + encodeURIComponent(file.name));
}
uploader.form.append('file', file, file.name), jQuery.ajax({
url: uploader.url, data: uploader.form, type: 'post', xhr: function (xhr) {
xhr = new XMLHttpRequest();
return xhr.upload.addEventListener('progress', function (event) {
file.xtotal = event.total, file.xloaded = event.loaded || 0;
that.progress((file.xloaded / file.xtotal * 100).toFixed(2), file)
}), xhr;
}, contentType: false, error: function () {
that.event('upload.error', {file: file}, file, '接口异常');
}, processData: false, success: function (ret) {
// 兼容数据格式
if (typeof ret === 'string' && ret.length > 0) try {
ret = JSON.parse(ret) || ret;
} catch (e) {
console.log(e)
}
if (typeof ret !== 'object') {
ret = {code: 1, url: file.xurl, info: '上传成功'};
}
/*! 检查单个文件上传返回的结果 */
if (typeof ret === 'object' && ret.code < 1) {
that.event('upload.error', {file: file}, file, ret.info || '上传失败');
} else {
that.done(ret, file.index, file, done, '上传成功');
}
}
});
} else if (parseInt(ret.code) === 200) {
(file.xurl = ret.data.url), that.progress('100.00', file);
that.done({code: 1, url: file.xurl, info: file.xstats}, file.index, file, done, '秒传成功');
} else {
that.event('upload.error', {file: file}, file, ret.info || ret.error.message || '上传出错!');
}
}
});
};
// 上传进度
Adapter.prototype.progress = function (number, file) {
this.event('upload.progress', {number: number, file: file});
if (file.notify) file.notify.setProgress(number);
};
// 上传结果
Adapter.prototype.done = function (ret, idx, file, done, message) {
/*! 检查单个文件上传返回的结果 */
if (ret.code < 1) return $.msg.tips(ret.info || '文件上传失败!');
if (typeof file.xurl !== 'string') return $.msg.tips('无效的文件上传对象!');
jQuery.post("{:url('admin/api.upload/done')}", {id: file.id, hash: file.xmd5});
/*! 单个文件上传成功结果处理 */
if (typeof done === 'function') {
done.call(this.option.elem, file.xurl, this.files['id']);
} else if (this.option.mult < 1 && this.option.elem.data('input')) {
$(this.option.elem.data('input')).val(file.xurl).trigger('change', file);
}
// 文件上传成功事件
this.event('push', file.xurl).event('upload.done', {file: file, data: ret}, file, message);
/*! 所有文件上传完成后结果处理 */
if (this.count.success + this.count.error >= this.count.total) {
this.option.hide || $.msg.close(this.loader);
if (this.option.mult > 0 && this.option.elem.data('input')) {
var urls = this.option.elem.data('input').value || [];
if (typeof urls === 'string') urls = urls.split('|');
for (var i in this.files) urls.push(this.files[i].xurl);
$(this.option.elem.data('input')).val(urls.join('|')).trigger('change', this.files);
}
this.event('upload.complete', {file: this.files}, file).init().uploader && this.uploader.reload();
}
};
/*! 触发事件过程 */
Adapter.prototype.event = function (name, data, file, message) {
if (name === 'upload.error') {
this.count.error++, file.xstate = -1, file.xstats = message;
if (file.notify) file.notify.setError(message || file.xstats || '');
} else if (name === 'upload.done') {
this.count.success++, file.xstate = 1, file.xstats = message;
if (file.notify) file.notify.setSuccess(message || file.xstats || '')
}
if (this.option.elem) {
this.option.elem.triggerHandler(name, data);
}
return this;
};
/**
* 计算文件 HASH
* @param {File} file 文件对象
* @return {Promise}
*/
Adapter.prototype.hash = function (file) {
var defer = jQuery.Deferred();
file.xext = file.name.indexOf('.') > -1 ? file.name.split('.').pop() : 'tmp';
/*! 兼容不能计算文件 HASH 的情况 */
var IsDate = '{$nameType|default=""}'.indexOf('date') > -1;
if (!window.FileReader || IsDate) return jQuery.when((function (xmd5, chars) {
while (xmd5.length < 32) xmd5 += chars.charAt(Math.floor(Math.random() * chars.length));
return SetFileXdata(file, xmd5, 6), defer.promise();
})(layui.util.toDateString(Date.now(), 'yyyyMMddHHmmss-'), '0123456789'));
/*! 读取文件并计算 HASH 值 */
return new LoadNextChunk(file).ReadAsChunk();
function SetFileXdata(file, xmd5, slice) {
file.xmd5 = xmd5, file.xstate = 0, file.xstats = '';
file.xkey = file.xmd5.substring(0, slice || 2) + '/' + file.xmd5.substring(slice || 2) + '.' + file.xext;
if (file.path) file.xkey = file.path + '/' + file.xkey;
return defer.resolve(file, file.xmd5, file.xkey), file;
}
function LoadNextChunk(file) {
var that = this, reader = new FileReader(), spark = new SparkMD5.ArrayBuffer();
var slice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
this.chunkIdx = 0, this.chunkSize = 2097152, this.chunkTotal = Math.ceil(file.size / this.chunkSize);
reader.onload = function (event) {
spark.append(event.target.result);
++that.chunkIdx < that.chunkTotal ? that.ReadAsChunk() : SetFileXdata(file, spark.end());
}, reader.onerror = function () {
defer.reject();
}, this.ReadAsChunk = function () {
this.start = that.chunkIdx * that.chunkSize;
this.loaded = this.start + that.chunkSize >= file.size ? file.size : this.start + that.chunkSize;
reader.readAsArrayBuffer(slice.call(file, this.start, this.loaded));
defer.notify(file, (this.loaded / file.size * 100).toFixed(2));
return defer.promise();
};
}
};
return UploadAdapter;
/**
* 上传状态提示扩展插件
* @param {File} file 文件对象
* @constructor
*/
function NotifyExtend(file) {
var that = this;
this.notify = Notify.notify({width: 260, title: file.name, showProgress: true, description: '上传进度 <span data-upload-progress>0%</span>', type: 'default', position: 'top-right', closeTimeout: 0});
this.$elem = $(this.notify.notification.nodes);
this.$elem.find('.growl-notification__progress').addClass('is-visible');
this.$elem.find('.growl-notification__progress-bar').addClass('transition');
this.setProgress = function (number) {
this.$elem.find('[data-upload-progress]').html(number + '%');
this.$elem.find('.growl-notification__progress-bar').css({width: number + '%'});
return this;
}, this.setError = function (message) {
this.$elem.find('.growl-notification__desc').html(message || '文件上传失败!');
this.$elem.removeClass('growl-notification--default').addClass('growl-notification--error')
return this.close();
}, this.setSuccess = function (message) {
this.setProgress('100.00');
this.$elem.find('.growl-notification__desc').html(message || '文件上传成功!');
this.$elem.removeClass('growl-notification--default').addClass('growl-notification--success');
return this.close();
}, this.close = function (timeout) {
return setTimeout(function () {
that.notify.close();
}, timeout || 2000), this;
};
}
});

View File

@ -1,152 +0,0 @@
<div class="image-dialog" id="ImageDialog">
<div class="image-dialog-head">
<div class="pull-left flex">
<input class="layui-input margin-right-5" v-model="keys" style="height:30px;line-height:30px" placeholder="请输入搜索关键词">
<a class="layui-btn layui-btn-sm layui-btn-normal" @click="search">搜 索</a>
</div>
<div class="pull-right">
<a class="layui-btn layui-btn-sm" @click="uploadImage">上传图片</a>
</div>
</div>
<div class="image-dialog-body">
<div class="image-dialog-item" v-for="x in items" v-if="show">
<div class="uploadimage" :style="x.style" @click="setValue(x.xurl)"></div>
<p class="image-dialog-item-name layui-elip" v-text="x.name"></p>
</div>
</div>
<div class="image-dialog-foot">
<div id="ImageDialogPage" class="image-dialog-page"></div>
</div>
</div>
<style>
.image-dialog-head {
clear: both;
height: 30px;
padding: 10px 12px;
}
.image-dialog-body {
height: 470px;
background: #efefef;
padding-top: 12px;
padding-left: 12px;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
}
.image-dialog-item {
position: relative;
margin-right: 12px;
margin-bottom: 12px;
}
.image-dialog-item-name {
left: 0;
right: 0;
bottom: 0;
color: #fff;
padding: 3px 10px;
position: absolute;
text-align: center;
line-height: 1.5em;
white-space: nowrap;
background: rgba(0, 0, 0, 0.6);
}
.image-dialog-item .uploadimage {
margin: 0;
width: 145px;
height: 145px;
}
.image-dialog-foot {
padding: 0 12px;
}
.image-dialog-page {
height: 50px;
text-align: center;
}
.image-dialog-page .layui-laypage a,
.image-dialog-page .layui-laypage span {
margin-bottom: 0;
}
</style>
<script>
require(['vue'], function (vue) {
var app = new vue({
el: '#ImageDialog',
data: {
page: 1,
limit: 15,
show: false,
$btn: null,
keys: '',
items: [],
},
created: function () {
this.$btn = $('#{$get.id|default=""}');
this.loadPage();
},
methods: {
// 创建分页工具条
addPage: function (count) {
var that = this;
this.show = true;
layui.laypage.render({
curr: this.page, count: count, limit: that.limit,
layout: ['count', 'prev', 'page', 'next', 'refresh'],
elem: 'ImageDialogPage', jump: function (obj, first) {
if (!first) that.loadPage(that.page = obj.curr);
},
});
},
// 搜索刷新数据
search: function () {
this.page = 1;
this.loadPage();
},
// 设置选择数据
setValue: function (url) {
this.$btn.trigger('choose', url);
if (this.$btn.data('input')) $(this.$btn.data('input')).val(url).trigger('change', url);
$('#ImageDialog').parents('.layui-layer-content').next().find('.layui-layer-close').trigger('click');
},
// 加载页面数据
loadPage: function () {
var that = this;
this.params = {page: this.page, limit: this.limit, output: 'layui.table', name: this.keys || ''};
$.form.load('{:url("image")}', this.params, 'get', function (ret) {
that.addPage(ret.count);
that.items = ret.data;
that.items.forEach(function (item) {
item.style = 'background-image:url(' + item.xurl + ')';
});
return false;
});
},
// 上传图片文件
uploadImage: function () {
$('[data-field="image-dialog-upload-input"]').click();
$('[name="image-dialog-upload-input"]').one('change', function (e) {
app.setValue(e.currentTarget.value);
// e.currentTarget.value 取上传后的值
// app.page = 1;
// app.loadPage();
});
},
}
});
});
</script>
<label class="layui-hide">
<!-- 图片上传组件 开始 -->
<input class="layui-input" name="image-dialog-upload-input">
<button class="layui-btn" data-file data-type="png,jpg,jpeg,gif" data-field="image-dialog-upload-input"></button>
<!-- 图片上传组件 结束 -->
</label>

View File

@ -1,136 +0,0 @@
<div class="image-dialog" id="ImageDialog">
<div class="image-dialog-head">
<div class="pull-left flex">
<input class="layui-input margin-right-5" v-model="keys" style="height:30px;line-height:30px" placeholder="请输入搜索关键词">
<a class="layui-btn layui-btn-sm layui-btn-normal" @click="search">搜 索</a>
</div>
<div class="pull-right">
<a class="layui-btn layui-btn-sm layui-btn-normal" @click="uploadImage">上传图片</a>
</div>
</div>
<div class="image-dialog-body">
<div class="image-dialog-item" v-for="x in list" @click="setItem(x)" style="display:none" v-show="show" :class="{'image-dialog-checked':x.checked}">
<div class="uploadimage" :style="x.style"></div>
<p class="image-dialog-item-name layui-elip" v-text="x.name"></p>
<span class="image-dialog-item-size">{{formatSize(x.size)}}</span>
<span class="image-dialog-item-type">{{x.xext.toUpperCase()}}</span>
</div>
</div>
<div class="image-dialog-foot">
<div id="ImageDialogPage" class="image-dialog-page"></div>
<div id="ImageDialogButton layui-hide" class="image-dialog-button layui-btn layui-btn-normal" v-if="data.length>0" @click="confirm">
已选 {{ data.length }} 张,确认
</div>
</div>
</div>
<script>
require(['vue'], function (vue) {
var app = new vue({
el: '#ImageDialog',
data: {
didx: 0,
page: 1, limit: 15, show: false, mult: false,
keys: '', list: [], data: [], idxs: {}, urls: [],
},
created: function () {
this.didx = $.msg.mdx.pop();
this.$btn = $('#{$get.id|default=""}');
this.$ups = $('#ImageDialogUploadLayout [data-file]');
this.mult = "{$get.file|default='image'}" === 'images';
this.loadPage(), setTimeout(function () {
$('#ImageDialogButton').removeClass('layui-hide');
}, 1000);
},
methods: {
// 搜索刷新数据
search: function () {
this.page = 1;
this.loadPage();
},
// 确认选择数据
confirm: function () {
this.urls = [];
this.data.forEach(function (file) {
app.setValue(file.xurl);
}), this.setInput();
},
// 格式文件大小
formatSize: function (size) {
return $.formatFileSize(size);
},
// 设置单项数据
setItem: function (item) {
if (!this.mult) {
this.setValue(item.xurl).setInput();
} else if ((item.checked = !this.idxs[item.id])) {
(this.idxs[item.id] = item) && this.data.push(item);
} else {
delete this.idxs[item.id];
this.data.forEach(function (temp, idx) {
temp.id === item.id && app.data.splice(idx, 1);
});
}
},
// 更新列表数据
setList: function (items, count) {
this.list = items;
this.list.forEach(function (item) {
item.checked = !!app.idxs[item.id]
item.style = 'background-image:url(' + item.xurl + ')';
}), this.addPage(count);
},
// 设置选择数据
setValue: function (xurl) {
$.msg.close(this.didx);
this.urls.push(xurl) && this.$btn.triggerHandler('push', xurl);
return this;
},
// 设置输入表单
setInput: function () {
if (this.$btn.data('input')) {
$(this.$btn.data('input')).val(this.urls.join('|')).trigger('change');
}
},
// 创建分页工具条
addPage: function (count) {
this.show = true;
layui.laypage.render({
curr: this.page, count: count, limit: app.limit,
layout: ['count', 'prev', 'page', 'next', 'refresh'],
elem: 'ImageDialogPage', jump: function (obj, first) {
if (!first) app.loadPage(app.page = obj.curr);
},
});
},
// 加载页面数据
loadPage: function () {
this.params = {page: this.page, limit: this.limit, output: 'layui.table', name: this.keys || ''};
this.params.type = '{$get.type|default="gif,png,jpg,jpeg"}';
$.form.load('{:url("image")}', this.params, 'get', function (ret) {
return app.setList(ret.data, ret.count), false;
});
},
// 上传图片文件
uploadImage: function () {
this.urls = [];
this.$ups.off('push').on('push', function (e, xurl) {
app.setValue(xurl);
}).off('upload.complete').on('upload.complete', function () {
app.setInput();
}).click();
},
}
});
});
</script>
<label class="layui-hide" id="ImageDialogUploadLayout">
<!-- 图片上传组件 开始 -->
{if isset($get.file) && $get.file eq 'image'}
<button class="layui-btn" data-file data-path="{$get.path|default=''}" data-type="png,jpg,jpeg,gif"></button>
{else}
<button class="layui-btn" data-file="mul" data-path="{$get.path|default=''}" data-type="png,jpg,jpeg,gif"></button>
{/if}
<!-- 图片上传组件 结束 -->
</label>

View File

@ -1,152 +0,0 @@
<div class="image-dialog" id="ImageDialog">
<div class="image-dialog-head">
<div class="pull-left flex">
<input class="layui-input margin-right-5" v-model="keys" style="height:30px;line-height:30px" placeholder="请输入搜索关键词">
<a class="layui-btn layui-btn-sm layui-btn-normal" @click="search">搜 索</a>
</div>
<div class="pull-right">
<a class="layui-btn layui-btn-sm" @click="uploadImage">上传图片</a>
</div>
</div>
<div class="image-dialog-body">
<div class="image-dialog-item" v-for="x in items" v-if="show">
<div class="uploadimage" :style="x.style" @click="setValue(x.xurl)"></div>
<p class="image-dialog-item-name layui-elip" v-text="x.name"></p>
</div>
</div>
<div class="image-dialog-foot">
<div id="ImageDialogPage" class="image-dialog-page"></div>
</div>
</div>
<style>
.image-dialog-head {
clear: both;
height: 30px;
padding: 10px 12px;
}
.image-dialog-body {
height: 470px;
background: #efefef;
padding-top: 12px;
padding-left: 12px;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
}
.image-dialog-item {
position: relative;
margin-right: 12px;
margin-bottom: 12px;
}
.image-dialog-item-name {
left: 0;
right: 0;
bottom: 0;
color: #fff;
padding: 3px 10px;
position: absolute;
text-align: center;
line-height: 1.5em;
white-space: nowrap;
background: rgba(0, 0, 0, 0.6);
}
.image-dialog-item .uploadimage {
margin: 0;
width: 145px;
height: 145px;
}
.image-dialog-foot {
padding: 0 12px;
}
.image-dialog-page {
height: 50px;
text-align: center;
}
.image-dialog-page .layui-laypage a,
.image-dialog-page .layui-laypage span {
margin-bottom: 0;
}
</style>
<script>
require(['vue'], function (vue) {
var app = new vue({
el: '#ImageDialog',
data: {
page: 1,
limit: 15,
show: false,
$btn: null,
keys: '',
items: [],
},
created: function () {
this.$btn = $('#{$get.id|default=""}');
this.loadPage();
},
methods: {
// 创建分页工具条
addPage: function (count) {
var that = this;
this.show = true;
layui.laypage.render({
curr: this.page, count: count, limit: that.limit,
layout: ['count', 'prev', 'page', 'next', 'refresh'],
elem: 'ImageDialogPage', jump: function (obj, first) {
if (!first) that.loadPage(that.page = obj.curr);
},
});
},
// 搜索刷新数据
search: function () {
this.page = 1;
this.loadPage();
},
// 设置选择数据
setValue: function (url) {
this.$btn.trigger('choose', url);
if (this.$btn.data('input')) $(this.$btn.data('input')).val(url).trigger('change', url);
$('#ImageDialog').parents('.layui-layer-content').next().find('.layui-layer-close').trigger('click');
},
// 加载页面数据
loadPage: function () {
var that = this;
this.params = {page: this.page, limit: this.limit, output: 'layui.table', name: this.keys || ''};
$.form.load('{:url("image")}', this.params, 'get', function (ret) {
that.addPage(ret.count);
that.items = ret.data;
that.items.forEach(function (item) {
item.style = 'background-image:url(' + item.xurl + ')';
});
return false;
});
},
// 上传图片文件
uploadImage: function () {
$('[data-field="image-dialog-upload-input"]').click();
$('[name="image-dialog-upload-input"]').one('change', function (e) {
app.setValue(e.currentTarget.value);
// e.currentTarget.value 取上传后的值
// app.page = 1;
// app.loadPage();
});
},
}
});
});
</script>
<label class="layui-hide">
<!-- 图片上传组件 开始 -->
<input class="layui-input" name="image-dialog-upload-input">
<button class="layui-btn" data-file data-type="png,jpg,jpeg,gif" data-field="image-dialog-upload-input"></button>
<!-- 图片上传组件 结束 -->
</label>

View File

@ -1,104 +0,0 @@
{extend name='main'}
{block name="content"}
<div class="think-box-shadow">
<ul id="zTree" class="ztree notselect"></ul>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" data-submit-role type='button'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' onclick="window.history.back()">取消编辑</button>
</div>
</div>
{/block}
{block name="script"}
<script>
require(['jquery.ztree'], function () {
new function () {
var that = this;
this.data = {}, this.ztree = null, this.setting = {
view: {showLine: false, showIcon: false, dblClickExpand: false},
check: {enable: true, nocheck: false, chkboxType: {"Y": "ps", "N": "ps"}}, callback: {
beforeClick: function (id, node) {
node.children.length < 1 ? that.ztree.checkNode(node, !node.checked, null, true) : that.ztree.expandNode(node);
return false;
}
}
};
this.renderChildren = function (list, level) {
var childrens = [];
for (var i in list) childrens.push({
open: true, node: list[i].node, name: list[i].title || list[i].node,
checked: list[i].checked || false, children: this.renderChildren(list[i]._sub_, level + 1)
});
return childrens;
};
this.getData = function () {
$.form.load('{:url("apply")}', {id: '{$vo.id}', action: 'get'}, 'post', function (ret) {
return (that.data = that.renderChildren(ret.data, 1)), that.showTree(), false;
});
};
this.showTree = function () {
this.ztree = $.fn.zTree.init($("#zTree"), this.setting, this.data);
while (true) {
var nodes = this.ztree.getNodesByFilter(function (node) {
return (!node.node && node.children.length < 1);
});
if (nodes.length < 1) break;
for (var i in nodes) this.ztree.removeNode(nodes[i]);
}
};
this.submit = function () {
var nodes = [], data = this.ztree.getCheckedNodes(true);
for (var i in data) if (data[i].node) nodes.push(data[i].node);
$.form.load('{:url("apply")}', {id: '{$vo.id}', action: 'save', nodes: nodes}, 'post');
};
// 刷新数据
this.getData();
// 提交表单
$('[data-submit-role]').on('click', function () {
that.submit();
});
};
});
</script>
{/block}
{block name="style"}
<style>
ul.ztree li {
white-space: normal !important;
}
ul.ztree li span.button.switch {
margin-right: 5px;
}
ul.ztree ul ul li {
display: inline-block;
white-space: normal;
}
ul.ztree > li {
padding: 15px 25px 15px 15px;
}
ul.ztree > li > ul {
margin-top: 12px;
border-top: 1px solid rgba(0, 0, 0, .1);
}
ul.ztree > li > ul > li {
padding: 5px;
}
ul.ztree > li > a > span {
font-weight: 700;
font-size: 15px;
}
ul.ztree .level2 .button.level2 {
background: 0 0;
}
</style>
{/block}

View File

@ -1,25 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="RoleTable">
<div class="layui-card-body padding-left-40">
<label class="layui-form-item relative block">
<span class="help-label"><b>权限名称</b>Permission Name</span>
<input maxlength="100" class="layui-input" name="title" value='{$vo.title|default=""}' required placeholder="请输入权限名称">
<span class="help-block">访问权限名称需要保持不重复,在给用户授权时需要根据名称选择!</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>权限描述</b>Permission Description</span>
<textarea placeholder="请输入权限描述" maxlength="200" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
</label>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,80 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-width="600px" data-table-id="RoleTable" class='layui-btn layui-btn-sm layui-btn-primary'>添加权限</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-table-id="RoleTable" data-rule="id#{id}" data-confirm="确定要批量删除权限吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='auth/index_search'}
<table id="RoleTable" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
// 初始化表格组件
$('#RoleTable').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'desc'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', align: 'center', width: 100, sort: true, templet: '#SortInputRoleTableTpl'},
{field: 'title', title: '权限名称', align: 'center', minWidth: 140},
{field: 'desc', title: '权限描述', align: 'center', minWidth: 110, templet: '<div>{{d.desc||"-"}}</div>'},
{field: 'status', title: '权限状态', align: 'center', minWidth: 110, templet: '#StatusSwitchRoleTableTpl'},
{field: 'create_at', title: '创建时间', align: 'center', minWidth: 170, sort: true},
{toolbar: '#ToolbarRoleTableTpl', title: '操作面板', align: 'center', minWidth: 210, fixed: 'right'},
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitchRoleTable)', function (obj) {
var data = {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
$.form.load("{:url('state')}", data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#RoleTable').trigger('reload');
});
return false;
}, false);
});
});
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputRoleTableTpl">
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchRoleTableTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitchRoleTable" {{-d.status>0?'checked':''}}>
<!--{else}-->
{{-d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 数据操作工具条模板 -->
<script type="text/html" id="ToolbarRoleTableTpl">
<!--{if auth('edit')}-->
<a class="layui-btn layui-btn-primary layui-btn-sm" data-event-dbclick data-width="600px" data-title="编辑权限" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("apply")}-->
<a class="layui-btn layui-btn-normal layui-btn-sm" data-open='{:url("apply")}?id={{d.id}}'>授 权</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除权限吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,45 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">权限名称</label>
<div class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入权限名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">权限描述</label>
<div class="layui-input-inline">
<input name="desc" value="{$get.desc|default=''}" placeholder="请输入权限描述" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">使用状态</label>
<div class="layui-input-inline">
<select class="layui-select" name="status">
<option value=''>-- 全部状态 --</option>
{foreach ['已禁用的权限','已激活的权限'] as $k=>$v}
{if isset($get.status) and $get.status eq $k.""}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>

View File

@ -1,68 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="BaseTable">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item label-required-prev">
<div class="help-label"><b>数据类型</b>DataType</div>
{if isset($vo.type)}
<label><input readonly value="{$vo.type|default=''}" class="layui-input think-bg-gray"></label>
{else}
<select class="layui-select" lay-filter="DataType">
{foreach $types as $type}{if (isset($vo.type) and $type eq $vo.type) or ($type eq input('get.type'))}
<option selected value="{$type}">{$type}</option>
{else}
<option value="{$type}">{$type}</option>
{/if}{/foreach}
</select>
<script>
(function (callable) {
layui.form.on('select(DataType)', callable);
callable({value: "{$vo.type|default=''}" || $('[lay-filter=DataType]').val()});
})(function (data) {
if (data.value === '--- 新增类型 ---') {
$('#DataTypeInput').removeClass('layui-hide').find('input').val('').focus();
} else {
$('#DataTypeInput').addClass('layui-hide').find('input').val(data.value);
}
});
</script>
{/if}
<p class="help-block">请选择数据类型,数据创建后不能再次修改哦 ~</p>
<div id="DataTypeInput" class="layui-hide relative">
<input class="layui-input" maxlength="20" name="type" required placeholder="请输入数据类型" value="{$vo.type|default=''}">
<p class="help-block">请输入新的数据类型,数据创建后不能再次修改哦 ~</p>
</div>
</div>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据编码</b>DataCode</span>
{if isset($vo.code)}
<input readonly maxlength="100" class="layui-input think-bg-gray" name="code" value='{$vo.code|default=""}' required placeholder="请输入数据编码">
{else}
<input maxlength="100" class="layui-input" name="code" value='{$vo.code|default=""}' required placeholder="请输入数据编码">
{/if}
<span class="help-block">请输入新的数据编码,数据创建后不能再次修改,同种数据类型的数据编码不能出现重复 ~</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据名称</b>DataName</span>
<input maxlength="500" class="layui-input" name="name" value='{$vo.name|default=""}' required placeholder="请输入数据名称">
<span class="help-block">请输入当前数据名称,请尽量保持名称的唯一性,数据名称尽量不要出现重复 ~</span>
</label>
<label class="layui-form-item relative block">
<span class="help-label"><b>数据内容</b>DataContent</span>
<textarea name="content" class="layui-textarea" placeholder="请输入数据内容">{$vo.content|default=''}</textarea>
</label>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,86 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("add")}-->
<button data-table-id="BaseTable" data-modal='{:url("add")}?type={$type|default=""}' class='layui-btn layui-btn-sm layui-btn-primary'>添加数据</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-table-id="BaseTable" data-action='{:url("remove")}' data-rule="id#{id}" data-confirm="确定要批量删除数据吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach $types as $t}{if isset($type) and $type eq $t}
<li class="layui-this" data-open="{:sysuri()}?type={$t}">{$t}</li>
{else}
<li data-open="{:sysuri()}?type={$t}">{$t}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
{include file='base/index_search'}
<table id="BaseTable" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
</div>
{/block}
{block name='script'}
<script>
$(function () {
// 初始化表格组件
$('#BaseTable').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'asc'},
where: {type: '{$type|default=""}'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTpl'},
// {field: 'type', title: '数据类型', minWidth: 140, align: 'center'},
{field: 'code', title: '数据编码', width: '20%', align: 'left'},
{field: 'name', title: '数据名称', width: '30%', align: 'left'},
{field: 'status', title: '数据状态', minWidth: 110, align: 'center', templet: '#StatusSwitchTpl'},
{field: 'create_at', title: '创建时间', minWidth: 170, align: 'center', sort: true},
{toolbar: '#toolbar', align: 'center', minWidth: 150, title: '数据操作', fixed: 'right'},
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (obj) {
var data = {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
$.form.load("{:url('state')}", data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#BaseTable').trigger('reload');
});
return false;
}, false);
});
});
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitch" {{-d.status>0?'checked':''}}>
<!--{else}-->
{{-d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 数据操作工具条模板 -->
<script type="text/html" id="toolbar">
<!--{if auth('edit')}-->
<a class="layui-btn layui-btn-primary layui-btn-sm" data-event-dbclick data-title="编辑数据" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,42 +0,0 @@
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">数据编码</label>
<div class="layui-input-inline">
<input name="code" value="{$get.code|default=''}" placeholder="请输入数据编码" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">数据名称</label>
<div class="layui-input-inline">
<input name="name" value="{$get.name|default=''}" placeholder="请输入数据名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">使用状态</label>
<div class="layui-input-inline">
<select class="layui-select" name="status">
<option value=''>-- 状态 --</option>
{foreach ['已禁用的权限','已激活的权限'] as $k=>$v}
{if isset($get.status) and $get.status eq $k.""}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>

View File

@ -1,179 +0,0 @@
{extend name="main"}
{block name="button"}
<!--{if isset($super) and $super}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-load="{:url('admin/api.system/config')}">清理无效配置</a>
<!--{/if}-->
<!--{if auth('system')}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-modal="{:url('system')}">修改系统参数</a>
<!--{/if}-->
{/block}
{block name="content"}
<!--{notempty name='super'}-->
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>运行模式</b><span class="color-desc font-s12 padding-left-5">Run Mode</span>
</div>
<div class="layui-card-body">
<div class="layui-btn-group shadow-mini nowrap">
<!--{if $app->isDebug()}-->
<a class="layui-btn layui-btn-sm layui-btn-active">以开发模式运行</a>
<a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="确定要切换到生产模式运行吗?" data-load="{:url('admin/api.system/debug')}?state=1">以生产模式运行</a>
<!--{else}-->
<a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="确定要切换到开发模式运行吗?" data-load="{:url('admin/api.system/debug')}?state=0">以开发模式运行</a>
<a class="layui-btn layui-btn-sm layui-btn-active">以生产模式运行</a>
<!--{/if}-->
</div>
<div class="margin-top-20">
<p><b>开发模式</b>:开发人员或在功能调试时使用,系统异常时会显示详细的错误信息,同时还会记录操作日志及数据库 SQL 语句信息。</p>
<p><b>生产模式</b>:项目正式部署上线后使用,系统异常时统一显示 “{:config('app.error_message')}”,只记录重要的异常日志信息,强烈推荐上线后使用此模式。</p>
</div>
</div>
</div>
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>富编辑器</b><span class="color-desc font-s12 padding-left-5">Rich Text Editor</span>
</div>
<div class="layui-card-body layui-clear">
<div class="layui-btn-group shadow-mini nowrap">
{if !in_array(sysconf('base.editor'),['ckeditor4','ckeditor5','auto'])}{php}sysconf('base.editor','ckeditor4');{/php}{/if}
{foreach ['ckeditor4'=>'CKEditor4','ckeditor5'=>'CKEditor5','auto'=>'自适应模式'] as $k => $v}{if sysconf('base.editor') eq $k}
{if auth('storage')}<a data-title="配置{$v}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
{else}
{if auth('storage')}<a data-title="配置{$v}" data-action="{:url('admin/api.system/editor')}" data-value="editor#{$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
{/if}{/foreach}
</div>
<div class="margin-top-20 nowrap full-width pull-left">
<p><b>CKEditor4</b>:旧版本编辑器,对浏览器兼容较好,但内容编辑体验稍有不足。</p>
<p><b>CKEditor5</b>:新版本编辑器,只支持新特性浏览器,对内容编辑体验较好,推荐使用。</p>
<p><b>自适应模式</b>:优先使用新版本编辑器,若浏览器不支持新版本时自动降级为旧版本编辑器。</p>
</div>
</div>
</div>
<!--{/notempty}-->
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>存储引擎</b><span class="color-desc font-s12 padding-left-5">Storage Engine</span>
</div>
<!-- 初始化存储配置 -->
{if !sysconf('storage.type')}{php}sysconf('storage.type','local');{/php}{/if}
{if !sysconf('storage.link_type')}{php}sysconf('storage.link_type','none');{/php}{/if}
{if !sysconf('storage.name_type')}{php}sysconf('storage.name_type','xmd5');{/php}{/if}
{if !sysconf('storage.allow_exts')}{php}sysconf('storage.allow_exts','doc,gif,ico,jpg,mp3,mp4,p12,pem,png,rar,xls,xlsx');{/php}{/if}
{if !sysconf('storage.local_http_protocol')}{php}sysconf('storage.local_http_protocol','http');{/php}{/if}
<div class="layui-card-body layui-clear">
<div class="layui-btn-group shadow-mini nowrap">
{foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','upyun'=>'又拍云USS存储','alioss'=>'阿里云OSS存储','txcos'=>'腾讯云COS存储'] as $k => $v}{if sysconf('storage.type') eq $k}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
{else}
{if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
{/if}{/foreach}
</div>
<div class="margin-top-20 nowrap full-width pull-left">
<p><b>本地服务器存储</b>:文件直接上传到本地服务器的 `static/upload` 目录,不支持大文件上传,占用服务器磁盘空间,访问时消耗服务器带宽流量。</p>
<p><b>七牛云对象存储</b>:文件直接上传到七牛云存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>又拍云USS存储</b>:文件直接上传到又拍云 USS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>阿里云OSS存储</b>:文件直接上传到阿里云 OSS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>腾讯云COS存储</b>:文件直接上传到腾讯云 COS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
</div>
</div>
</div>
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>系统参数</b><span class="color-desc font-s12 padding-left-5">System Parameter</span>
</div>
<div class="layui-card-body">
<div class="layui-form-item">
<div class="help-label"><b>网站名称</b>Website</div>
<label class="relative block">
<input readonly value="{:sysconf('site_name')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('site_name')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站名称及网站图标,将显示在浏览器的标签上。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>管理程序名称</b>Name</div>
<label class="relative block">
<input readonly value="{:sysconf('app_name')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('app_name')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">管理程序名称,将显示在后台左上角标题。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>管理程序版本</b>Version</div>
<label class="relative block">
<input readonly value="{:sysconf('app_version')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('app_version')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">管理程序版本,将显示在后台左上角标题。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>公网备案号</b>Baian</div>
<label class="relative block">
<input readonly value="{:sysconf('beian')?:'-'}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('beian')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<p class="help-block">公网备案号,可以在 <a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a> 查询获取,将在登录页面下面显示。</p>
</div>
<div class="layui-form-item">
<div class="help-label"><b>网站备案号</b>Miitbeian</div>
<label class="relative block">
<input readonly value="{:sysconf('miitbeian')?:'-'}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('miitbeian')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站备案号,可以在 <a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a> 查询获取,将显示在登录页面下面。</div>
</div>
<div class="layui-form-item">
<div class="help-label"><b>网站版权信息</b>Copyright</div>
<label class="relative block">
<input readonly value="{:sysconf('site_copy')}" class="layui-input layui-bg-gray">
<a data-copy="{:sysconf('site_copy')}" class="layui-icon layui-icon-release input-right-icon"></a>
</label>
<div class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统。</div>
</div>
</div>
</div>
<!--{if $app->isDebug()}-->
<div class="layui-card padding-20 shadow">
<div class="layui-card-header notselect">
<b>系统信息</b><span class="color-desc font-s12 padding-left-5">System Information</span>
</div>
<div class="layui-card-body">
<table class="layui-table" lay-even>
<tbody>
<tr>
<th class="nowrap text-center">核心框架</th>
<td><a target="_blank" href="https://www.thinkphp.cn">ThinkPHP Version {$app->version()}</a></td>
</tr>
<tr>
<th class="nowrap text-center">管理程序</th>
<td><a target="_blank" href="https://thinkadmin.top">ThinkAdmin Version {$version|default='6.0.0'}</a></td>
</tr>
<tr>
<th class="nowrap text-center">服务器信息</th>
<td>{:php_uname()}</td>
</tr>
<tr>
<th class="nowrap text-center">服务器软件</th>
<td>{$request->server('SERVER_SOFTWARE',php_sapi_name())}</td>
</tr>
<tr>
<th class="nowrap text-center">PHP 版本</th>
<td>PHP Version {$Think.const.PHP_VERSION}</td>
</tr>
<tr>
<th class="nowrap text-center">MySQL 版本</th>
<td>MySQL Version {$app->db->query('SELECT VERSION()')[0]['VERSION()']}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!--{/if}-->
{/block}

View File

@ -1,45 +0,0 @@
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">命名方式</b><br><span class="nowrap color-desc">NameType</span>
</label>
<div class="layui-input-block">
{foreach ['xmd5'=>'文件哈希值 ( 支持秒传 )','date'=>'日期+随机 ( 普通上传 )'] as $k=>$v}
<label class="think-radio notselect">
{if sysconf('storage.name_type') eq $k}
<input checked type="radio" name="storage.name_type" value="{$k}" lay-ignore> {$v}
{else}
<input type="radio" name="storage.name_type" value="{$k}" lay-ignore> {$v}
{/if}
</label>
{/foreach}
<p class="help-block">类型为“文件哈希”时可以实现文件秒传功能,同一个文件只需上传一次节省存储空间,推荐使用。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">链接类型</b><br><span class="nowrap color-desc">LinkType</span>
</label>
<div class="layui-input-block">
{foreach ['none'=>'简洁链接','full'=>'完整链接','none+compress'=>'简洁并压缩图片','full+compress'=>'完整并压缩图片'] as $k=>$v}
<label class="think-radio notselect">
{if sysconf('storage.link_type') eq $k}
<input checked type="radio" name="storage.link_type" value="{$k}" lay-ignore> {$v}
{else}
<input type="radio" name="storage.link_type" value="{$k}" lay-ignore> {$v}
{/if}
</label>
{/foreach}
<p class="help-block">类型为“简洁链接”时链接将只返回 hash 地址,而“完整链接”将携带参数保留文件名,图片压缩功能云平台会单独收费。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.allow_exts">
<b class="color-green">允许类型</b><br><span class="nowrap color-desc">AllowExts</span>
</label>
<div class="layui-input-block">
<input id="storage.allow_exts" type="text" name="storage.allow_exts" required value="{:sysconf('storage.allow_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
<p class="help-block">设置系统允许上传文件的后缀多个以英文逗号隔开如png,jpg,rar,doc未设置允许上传的后缀</p>
</div>
</div>

View File

@ -1,96 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-top-20">
<div class="color-text layui-code text-center layui-bg-gray" style="border-left-width:1px;margin:0 0 15px 40px">
<p class="margin-bottom-5 font-w7">文件将上传到 <a target="_blank" href="https://www.aliyun.com/minisite/goods?taskCode=shareNew2205&recordId=3646641&userCode=ztlqlu4v">阿里云</a> OSS 存储,需要配置 OSS 公开访问及跨域策略</p>
<p>配置跨域访问 CORS 规则,设置:来源 Origin 为 *,允许 Methods 为 POST允许 Headers 为 *</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">访问协议</b><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.alioss_http_protocol')}{php}sysconf('storage.alioss_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.alioss_http_protocol') eq $protocol}
<input checked type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">阿里云OSS存储访问协议其中 HTTPS 需要配置证书才能使用AUTO 为相对协议)</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<b class="color-green">存储区域</b><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
<select class="layui-select" name="storage.alioss_point" lay-search>
{foreach $points as $point => $title}
{if sysconf('storage.alioss_point') eq $point}
<option selected value="{$point}">{$title} {$point} </option>
{else}
<option value="{$point}">{$title} {$point} </option>
{/if}{/foreach}
</select>
<p class="help-block">阿里云OSS存储空间所在区域需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_bucket">
<b class="color-green">空间名称</b><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_bucket" type="text" name="storage.alioss_bucket" required value="{:sysconf('storage.alioss_bucket')}" placeholder="请输入阿里云OSS存储 Bucket (空间名称)" class="layui-input">
<p class="help-block">填写阿里云OSS存储空间名称think-admin-oss需要是全区唯一的值不存在时会自动创建</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_http_domain">
<b class="color-green">访问域名</b><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_http_domain" type="text" name="storage.alioss_http_domain" required value="{:sysconf('storage.alioss_http_domain')}" placeholder="请输入阿里云OSS存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写阿里云OSS存储外部访问域名static.alioss.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_access_key">
<b class="color-green">访问密钥</b><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_access_key" type="text" name="storage.alioss_access_key" required value="{:sysconf('storage.alioss_access_key')}" placeholder="请输入阿里云OSS存储 AccessKey (访问密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.alioss_secret_key">
<b class="color-green">安全密钥</b><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.alioss_secret_key" type="text" name="storage.alioss_secret_key" required value="{:sysconf('storage.alioss_secret_key')}" maxlength="43" placeholder="请输入阿里云OSS存储 SecretKey (安全密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="alioss">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,49 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-top-20">
<div class="color-text layui-code text-center layui-bg-gray" style="border-left-width:1px;margin:0 0 15px 40px">
<p class="margin-bottom-5 font-w7">文件将存储在本地服务器,默认保存在 public/upload 目录,文件以 HASH 命名。</p>
<p>文件存储的目录需要有读写权限,有足够的存储空间。<span class="color-red">特别注意,本地存储暂不支持图片压缩!</span></p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">访问协议</b><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.local_http_protocol')}{php}sysconf('storage.local_http_protocol','http');{/php}{/if}
{foreach ['follow'=>'FOLLOW','http'=>'HTTP','https'=>'HTTPS','path'=>'PATH','auto'=>'AUTO'] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.local_http_protocol') eq $protocol}
<input checked type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">本地存储访问协议,其中 HTTPS 需要配置证书才能使用( FOLLOW 跟随系统PATH 文件路径AUTO 相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.local_http_domain">
<b class="color-green">访问域名</b><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.local_http_domain" type="text" name="storage.local_http_domain" value="{:sysconf('storage.local_http_domain')}" placeholder="请输入上传后的访问域名 (非必填项)" class="layui-input">
<p class="help-block">填写上传后的访问域名不指定时根据当前访问地址自动计算static.thinkadmin.top</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="local">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,95 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-top-20">
<div class="color-text layui-code text-center layui-bg-gray" style="border-left-width:1px;margin:0 0 15px 40px">
<p class="margin-bottom-5 font-w7">文件将上传到 <a target="_blank" href="https://s.qiniu.com/rYr26v">七牛云</a> 存储,对象存储需要配置为公开访问的 Bucket 空间</p>
完成实名认证后可获得 10G 免费存储空间哦!<a target="_blank" href="https://s.qiniu.com/rYr26v">我要免费申请</a>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">访问协议</b><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.qiniu_http_protocol')}{php}sysconf('storage.qiniu_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.qiniu_http_protocol') eq $protocol}
<input checked type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">七牛云存储访问协议,其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<b class="color-green">存储区域</b><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
<select class="layui-select" name="storage.qiniu_region" lay-search>
{foreach $points as $point => $title}
{if sysconf('storage.qiniu_region') eq $point}
<option selected value="{$point}">{$title} {$point} </option>
{else}
<option value="{$point}">{$title} {$point} </option>
{/if}{/foreach}
</select>
<p class="help-block">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_bucket">
<b class="color-green">空间名称</b><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_bucket" type="text" name="storage.qiniu_bucket" required value="{:sysconf('storage.qiniu_bucket')}" placeholder="请输入七牛云存储 Bucket (空间名称)" class="layui-input">
<p class="help-block">填写七牛云存储空间名称static</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_http_domain">
<b class="color-green">访问域名</b><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_http_domain" type="text" name="storage.qiniu_http_domain" required value="{:sysconf('storage.qiniu_http_domain')}" placeholder="请输入七牛云存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写七牛云存储访问域名static.qiniu.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_access_key">
<b class="color-green">访问密钥</b><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_access_key" type="text" name="storage.qiniu_access_key" required value="{:sysconf('storage.qiniu_access_key')}" placeholder="请输入七牛云授权 AccessKey (访问密钥)" class="layui-input">
<p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.qiniu_secret_key">
<b class="color-green">安全密钥</b><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.qiniu_secret_key" type="text" name="storage.qiniu_secret_key" required value="{:sysconf('storage.qiniu_secret_key')}" maxlength="43" placeholder="请输入七牛云授权 SecretKey (安全密钥)" class="layui-input">
<p class="help-block">可以在 [ 七牛云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="qiniu">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,96 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-top-20">
<div class="color-text layui-code text-center layui-bg-gray" style="border-left-width:1px;margin:0 0 15px 40px">
<p class="margin-bottom-5 font-w7">文件将上传到 <a target="_blank" href="https://curl.qcloud.com/4t0Mbw2K">腾讯云</a> COS 存储,需要配置 COS 公有读私有写访问权限及跨域策略</p>
<p>配置跨域访问 CORS 规则,设置来源 Origin 为 *,允许 Methods 为 POST允许 Headers 为 *</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">访问协议</b><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.txcos_http_protocol')}{php}sysconf('storage.txcos_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.txcos_http_protocol') eq $protocol}
<input checked type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">腾讯云COS存储访问协议其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 </p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">
<b class="color-green">存储区域</b><br><span class="nowrap color-desc label-required">Region</span>
</label>
<div class="layui-input-block">
<select class="layui-select" name="storage.txcos_point" lay-search>
{foreach $points as $point => $title}
{if sysconf('storage.txcos_point') eq $point}
<option selected value="{$point}">{$title} {$point} </option>
{else}
<option value="{$point}">{$title} {$point} </option>
{/if}{/foreach}
</select>
<p class="help-block">腾讯云COS存储空间所在区域需要严格对应储存所在区域才能上传文件</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_bucket">
<b class="color-green">空间名称</b><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_bucket" type="text" name="storage.txcos_bucket" required value="{:sysconf('storage.txcos_bucket')}" placeholder="请输入腾讯云COS存储 Bucket" class="layui-input">
<p class="help-block">填写腾讯云COS存储空间名称thinkadmin-1251143395</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_http_domain">
<b class="color-green">访问域名</b><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_http_domain" type="text" name="storage.txcos_http_domain" required value="{:sysconf('storage.txcos_http_domain')}" placeholder="请输入腾讯云COS存储 Domain" class="layui-input">
<p class="help-block">填写腾讯云COS存储外部访问域名static.txcos.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_access_key">
<b class="color-green">访问密钥</b><br><span class="nowrap color-desc">AccessKey</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_access_key" type="text" name="storage.txcos_access_key" required value="{:sysconf('storage.txcos_access_key')}" placeholder="请输入腾讯云COS存储 AccessKey" class="layui-input">
<p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到访问密钥</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.txcos_secret_key">
<b class="color-green">安全密钥</b><br><span class="nowrap color-desc">SecretKey</span>
</label>
<div class="layui-input-block">
<input id="storage.txcos_secret_key" type="text" name="storage.txcos_secret_key" required value="{:sysconf('storage.txcos_secret_key')}" maxlength="43" placeholder="请输入腾讯云COS存储 SecretKey" class="layui-input">
<p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到安全密钥</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="txcos">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,79 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-top-20">
<div class="color-text layui-code text-center layui-bg-gray" style="border-left-width:1px;margin:0 0 15px 40px">
<p class="margin-bottom-5 font-w7">文件将上传到 <a target="_blank" href="https://console.upyun.com/register/?invite=PN1cRmjRb">又拍云</a> USS 存储,需要配置 USS 公开访问及跨域策略</p>
<p>配置跨域访问 CORS 规则,设置来源 Origin 为 *,允许 Methods 为 POST允许 Headers 为 *</p>
</div>
{include file='config/storage-0'}
<div class="layui-form-item">
<label class="layui-form-label label-required">
<b class="color-green">访问协议</b><br><span class="nowrap color-desc">Protocol</span>
</label>
<div class="layui-input-block">
{if !sysconf('storage.upyun_http_protocol')}{php}sysconf('storage.upyun_http_protocol','http');{/php}{/if}
{foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
<label class="think-radio">
{if sysconf('storage.upyun_http_protocol') eq $protocol}
<input checked type="radio" name="storage.upyun_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{else}
<input type="radio" name="storage.upyun_http_protocol" value="{$protocol}" lay-ignore> {$remark}
{/if}
</label>
{/foreach}
<p class="help-block">又拍云存储访问协议,其中 HTTPS 需要配置证书才能使用AUTO 为相对协议)</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.upyun_bucket">
<b class="color-green">空间名称</b><br><span class="nowrap color-desc">Bucket</span>
</label>
<div class="layui-input-block">
<input id="storage.upyun_bucket" name="storage.upyun_bucket" required value="{:sysconf('storage.upyun_bucket')}" placeholder="请输入又拍云存储 Bucket (空间名称)" class="layui-input">
<p class="help-block">填写又拍云存储空间名称think-admin-uss需要是全区唯一的值不存在时会自动创建</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.upyun_http_domain">
<b class="color-green">访问域名</b><br><span class="nowrap color-desc">Domain</span>
</label>
<div class="layui-input-block">
<input id="storage.upyun_http_domain" name="storage.upyun_http_domain" required value="{:sysconf('storage.upyun_http_domain')}" placeholder="请输入又拍云存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写又拍云存储外部访问域名static.uss.thinkadmin.top</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.upyun_access_key">
<b class="color-green">操作账号</b><br><span class="nowrap color-desc">Username</span>
</label>
<div class="layui-input-block">
<input id="storage.upyun_access_key" name="storage.upyun_access_key" required value="{:sysconf('storage.upyun_access_key')}" maxlength="100" placeholder="请输入又拍云存储 Username (操作员账号)" class="layui-input">
<p class="help-block">可以在 [ 账户管理 > 操作员 ] 设置操作员账号并将空间给予授权。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="storage.upyun_secret_key">
<b class="color-green">操作密码</b><br><span class="nowrap color-desc">Password</span>
</label>
<div class="layui-input-block">
<input id="storage.upyun_secret_key" name="storage.upyun_secret_key" required value="{:sysconf('storage.upyun_secret_key')}" maxlength="100" placeholder="请输入又拍云存储 Password (操作员密码)" class="layui-input">
<p class="help-block">可以在 [ 账户管理 > 操作员 ] 设置操作员密码并将空间给予授权</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<input type="hidden" name="storage.type" value="upyun">
<div class="layui-form-item text-center padding-left-40">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</div>
</form>

View File

@ -1,113 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-left-40">
<div class="layui-row layui-col-space15 margin-bottom-5">
<div class="layui-col-xs4 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>登录表单标题</b>Login Name</span>
<input name="login_name" required placeholder="请输入登录页面的表单标题" value="{:sysconf('login_name')?:'系统管理'}" class="layui-input">
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<div class="help-label label-required-prev"><b>后台登录入口</b>Login Entry</div>
<label class="layui-input relative block nowrap label-required-null">
<span>{:sysuri('@',[],false,true)}</span>
<input autofocus required pattern="[a-zA-Z_][a-zA-Z0-9_]*" placeholder="请输入后台登录入口" class="layui-input inline-block padding-0 border-0" style="width:100px;background:none" value="{:substr(sysuri('admin/index/index',[],false), strlen(sysuri('@')))}" name="xpath">
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<div class="help-label label-required-prev"><b>后台默认配色</b>Theme Style</div>
<select class="layui-select" name="site_theme" lay-filter="SiteTheme">
{foreach $themes as $k=>$v}{if sysconf('base.site_theme') eq $k}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
<div class="layui-col-xs12 padding-top-0 padding-bottom-0">
<span class="help-block">后台登录入口是由英文字母开头,且不能有相同名称的模块,设置之后原地址不能继续访问,请谨慎配置 ~</span>
</div>
</div>
<div class="layui-form-item margin-bottom-5">
<div class="help-label"><b>登录背景图片</b>Background Image</div>
<div class="layui-textarea help-images">
<input type="hidden" value="{:sysconf('login_image')}" name="login_image">
</div>
</div>
<div class="layui-form-item margin-bottom-5">
<div class="help-label label-required-prev"><b>浏览器小图标</b>Browser Icon</div>
<label class="relative block label-required-null">
<input class="layui-input" required pattern="^(http|/)" placeholder="请上传浏览器图标" value="{:sysconf('site_icon')}" name="site_icon">
<a class="input-right-icon layui-icon layui-icon-upload-drag" data-file="btn" data-type="png,jpg,jpeg" data-field="site_icon"></a>
</label>
<div class="help-block sub-span-blue">
建议上传 <span>128x128</span><span>256x256</span><span>JPG</span>,<span>PNG</span>,<span>JPEG</span> 图片,保存后会自动生成 <span>48x48</span><span>ICO</span> 文件 ~
</div>
</div>
<div class="layui-row layui-col-space15 margin-bottom-5">
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item margin-bottom-5 relative block">
<span class="help-label"><b>网站名称</b>Site Name</span>
<input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
<span class="help-block">网站名称将显示在浏览器的标签上 ~</span>
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item margin-bottom-5 relative block">
<span class="help-label"><b>后台程序名称</b>App Name</span>
<input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
<span class="help-block">管理程序名称显示在后台左上标题处 ~</span>
</label>
</div>
<div class="layui-col-xs4 padding-bottom-0">
<label class="layui-form-item margin-bottom-5 relative block">
<span class="help-label"><b>后台程序版本</b>App Version</span>
<input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
<span class="help-block">管理程序版本显示在后台左上标题处 ~</span>
</label>
</div>
<div class="layui-col-xs4 padding-top-0 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>公网安备号</b>Baian</span>
<input name="beian" placeholder="请输入公网安备号" value="{:sysconf('beian')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs4 padding-top-0 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>网站备案号</b>Miitbeian</span>
<input name="miitbeian" placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs4 padding-top-0 padding-bottom-0">
<label class="relative block">
<span class="help-label"><b>网站版权信息</b>Copyright</span>
<input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
</label>
</div>
<div class="layui-col-xs12 help-block padding-top-0">
网站备案号和公安备案号可以在<a target="_blank" href="https://beian.miit.gov.cn">备案管理中心</a>查询并获取,网站上线时必需配置备案号,备案号会链接到信息备案管理系统 ~
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
</div>
</form>
<script>
$('[name=login_image]').uploadMultipleImage();
layui.form.on('select(SiteTheme)', function (data) {
var alls = '', prox = 'layui-layout-theme-', curt = prox + data.value;
$(data.elem.options).map(function () {
if (this.value !== data.value) alls += ' ' + prox + this.value;
});
$('.layui-layout-body').removeClass(alls).addClass(curt)
});
</script>

View File

@ -1,568 +0,0 @@
<?php
if (!function_exists('parse_padding')) {
function parse_padding($source)
{
$length = strlen(strval(count($source['source']) + $source['first']));
return 40 + ($length - 1) * 8;
}
}
if (!function_exists('parse_class')) {
function parse_class($name): string
{
$names = explode('\\', $name);
return '<abbr title="' . $name . '">' . end($names) . '</abbr>';
}
}
if (!function_exists('parse_file')) {
function parse_file($file, $line): string
{
return '<a class="toggle" title="' . "{$file} line {$line}" . '">' . basename($file) . " line {$line}" . '</a>';
}
}
if (!function_exists('parse_args')) {
function parse_args($args): string
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
}
return implode(', ', $result);
}
}
if (!function_exists('echo_value')) {
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>系统发生错误</title>
<meta name="robots" content="noindex,nofollow"/>
<style>
/* Base */
body {
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 0 20px 20px;
}
h1 {
margin: 10px 0 0;
font-size: 28px;
font-weight: 500;
line-height: 32px;
}
h2 {
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 18px;
border-bottom: 1px solid #eee;
}
h3 {
margin: 12px;
font-size: 16px;
font-weight: bold;
}
abbr {
cursor: help;
text-decoration: underline;
text-decoration-style: dotted;
}
a {
color: #868686;
cursor: pointer;
}
a:hover {
text-decoration: underline;
}
.line-error {
background: #f8cbcb;
}
.echo table {
width: 100%;
}
.echo pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border: 0;
border-radius: 3px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.echo pre > pre {
padding: 0;
margin: 0;
}
/* Exception Info */
.exception {
margin-top: 20px;
}
.exception .message {
padding: 12px;
border: 1px solid #ddd;
border-bottom: 0 none;
line-height: 18px;
font-size: 16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .code {
float: left;
text-align: center;
color: #fff;
margin-right: 12px;
padding: 16px;
border-radius: 4px;
background: #999;
}
.exception .source-code {
padding: 6px;
border: 1px solid #ddd;
background: #f9f9f9;
overflow-x: auto;
}
.exception .source-code pre {
margin: 0;
}
.exception .source-code pre ol {
margin: 0;
color: #4288ce;
display: inline-block;
min-width: 100%;
box-sizing: border-box;
font-size: 14px;
font-family: "Century Gothic", Consolas, "Liberation Mono", Courier, Verdana, serif;
padding-left: <?php echo (isset($source) && ! empty($source)) ? parse_padding($source): 40;?> px;
}
.exception .source-code pre li {
border-left: 1px solid #ddd;
height: 18px;
line-height: 18px;
}
.exception .source-code pre code {
color: #333;
height: 100%;
display: inline-block;
border-left: 1px solid #fff;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace {
padding: 6px;
border: 1px solid #ddd;
border-top: 0 none;
line-height: 16px;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace h2:hover {
text-decoration: underline;
cursor: pointer;
}
.exception .trace ol {
margin: 12px;
}
.exception .trace ol li {
padding: 2px 4px;
}
.exception div:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
/* Exception Variables */
.exception-var table {
width: 100%;
margin: 12px 0;
box-sizing: border-box;
table-layout: fixed;
word-wrap: break-word;
}
.exception-var table caption {
text-align: left;
font-size: 16px;
font-weight: bold;
padding: 6px 0;
}
.exception-var table caption small {
font-weight: 300;
display: inline-block;
margin-left: 10px;
color: #ccc;
}
.exception-var table tbody {
font-size: 13px;
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑", serif;
}
.exception-var table td {
padding: 0 6px;
vertical-align: top;
word-break: break-all;
}
.exception-var table td:first-child {
width: 28%;
font-weight: bold;
white-space: nowrap;
}
.exception-var table td pre {
margin: 0;
}
/* Copyright Info */
.copyright {
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
/* SPAN elements with the classes below are added by prettyprint. */
pre.prettyprint .pln {
color: #000
}
/* plain text */
pre.prettyprint .str {
color: #080
}
/* string content */
pre.prettyprint .kwd {
color: #008
}
/* a keyword */
pre.prettyprint .com {
color: #800
}
/* a comment */
pre.prettyprint .typ {
color: #606
}
/* a type name */
pre.prettyprint .lit {
color: #066
}
/* a literal value */
/* punctuation, lisp open bracket, lisp close bracket */
pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo {
color: #660
}
pre.prettyprint .tag {
color: #008
}
/* a markup tag name */
pre.prettyprint .atn {
color: #606
}
/* a markup attribute name */
pre.prettyprint .atv {
color: #080
}
/* a markup attribute value */
pre.prettyprint .dec, pre.prettyprint .var {
color: #606
}
/* a declaration; a variable name */
pre.prettyprint .fun {
color: red
}
/* a function name */
</style>
</head>
<body>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="info">
<div>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
</div>
</div>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php">
<ol start="<?php echo $trace['source']['first']; ?>"><!--<?php foreach ((array)$trace['source']['source'] as $key => $value) { ?>--><li class="line-<?php echo " {$index}-" . ($key + $trace['source']['first']) . ($trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''); ?>"><code><?php echo htmlentities($value); ?></code></li><!--<?php } ?>--></ol>
</pre>
</div>
<?php } ?>
<div class="trace">
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array)$trace['trace'] as $value) { ?>
<li>
<?php
// Show Function
if ($value['function']) {
echo sprintf('at %s%s%s(%s)', isset($value['class']) ? parse_class($value['class']) : '', $value['type'] ?? '', $value['function'], isset($value['args']) ? parse_args($value['args']) : '');
}
// Show line
if (isset($value['file']) && isset($value['line'])) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
<?php } ?>
</ol>
</div>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info"><h1><?php echo htmlentities(isset($message) ? $message : ''); ?></h1></div>
</div>
<?php } ?>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array)$datas as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array)$value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array)$tables as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array)$value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (\think\facade\App::isDebug()) { ?>
<script>
function $(selector, node) {
var elements;
node = node || document;
if (document.querySelectorAll) {
elements = node.querySelectorAll(selector);
} else {
switch (selector.substr(0, 1)) {
case '#':
elements = [node.getElementById(selector.substr(1))];
break;
case '.':
if (document.getElementsByClassName) {
elements = node.getElementsByClassName(selector.substr(1));
} else {
elements = get_elements_by_class(selector.substr(1), node);
}
break;
default:
elements = node.getElementsByTagName();
}
}
return elements;
function get_elements_by_class(search_class, node, tag) {
var elements = [], eles,
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
node = node || document;
tag = tag || '*';
eles = node.getElementsByTagName(tag);
for (var i = 0; i < eles.length; i++) {
if (pattern.test(eles[i].className)) {
elements.push(eles[i])
}
}
return elements;
}
}
$.getScript = function (src, func) {
var script = document.createElement('script');
script.async = 'async';
script.src = src;
script.onload = func || function () {
};
$('head')[0].appendChild(script);
}
;(function () {
var files = $('.toggle');
var ol = $('ol', $('.prettyprint')[0]);
var li = $('li', ol[0]);
// 短路径和长路径变换
for (var i = 0; i < files.length; i++) {
files[i].ondblclick = function () {
var title = this.title;
this.title = this.innerHTML;
this.innerHTML = title;
}
}
(function () {
var expand = function (dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function () {
expand(this);
};
}
})();
$.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function () {
prettyPrint();
});
})();
</script>
<?php } ?>
</body>
</html>

View File

@ -1,62 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("distinct")}-->
<a data-table-id="FileTable" data-load='{:url("distinct")}' class='layui-btn layui-btn-sm layui-btn-primary'>清理重复</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a data-confirm="确定永久删除这些账号吗?" data-table-id="FileTable" data-action='{:url("remove")}' data-rule="id#{id}" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</a>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='file/index_search'}
<table id="FileTable" data-url="{:sysuri('index')}" data-target-search="form.form-search"></table>
</div>
<script>
$(function () {
$('#FileTable').layTable({
even: true, height: 'full',
sort: {field: 'id', type: 'desc'},
cols: [[
{checkbox: true, fixed: true},
{field: 'id', title: 'ID', width: 80, align: 'center', sort: true},
{field: 'name', title: '文件名称', width: '12%', align: 'center'},
{field: 'hash', title: '文件哈希', width: '15%', align: 'center', templet: '<div><code>{{d.hash}}</code></div>'},
{
field: 'size', title: '文件大小', align: 'center', width: '8%', sort: true, templet: function (d) {
return $.formatFileSize(d.size)
}
},
{field: 'xext', title: '文件后缀', align: 'center', width: '8%', sort: true},
{
field: 'xurl', title: '查看文件', width: '8%', align: 'center', templet: function (d) {
if (typeof d.mime === 'string' && /^image\//.test(d.mime)) {
return laytpl('<div class="headimg headimg-no headimg-ss margin-0" data-tips-hover data-tips-image="{{d.xurl}}" style="background-image:url({{d.xurl}})"></div>').render(d)
} else if (typeof d.mime === 'string' && /^(video|audio)\//.test(d.mime)) {
return laytpl('<div><a target="_blank" data-iframe="{{d.xurl}}" data-title="查看媒体">查看</a></div>').render(d);
} else {
return laytpl('<div><a target="_blank" href="{{d.xurl}}">查看</a></div>').render(d);
}
}
},
{
field: 'isfast', title: '上传方式', align: 'center', width: '8%', templet: function (d) {
return d.isfast ? '<b class="color-green">秒传</b>' : '<b class="color-blue">普通</b>';
}
},
{field: 'ctype', title: '存储方式', align: 'center', width: '10%'},
{field: 'create_at', title: '上传时间', align: 'center', width: '15%', sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 90, fixed: 'right'}
]]
});
});
</script>
<script type="text/html" id="toolbar">
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-sm layui-btn-danger" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,58 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">文件名称</label>
<label class="layui-input-inline">
<input name="name" value="{$get.name|default=''}" placeholder="请输入文件名称" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">文件哈希</label>
<label class="layui-input-inline">
<input name="hash" value="{$get.hash|default=''}" placeholder="请输入文件哈希" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">文件后缀</label>
<div class="layui-input-inline">
<select name="xext" lay-search class="layui-select">
<option value=''>-- 全部后缀 --</option>
{foreach $xexts as $v}{if isset($get.xext) and $k eq $get.xext}
<option selected value="{$v}">{$v}</option>
{else}
<option value="{$v}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">存储方式</label>
<div class="layui-input-inline">
<select name="type" lay-search class="layui-select">
<option value=''>-- 全部方式 --</option>
{foreach $types as $k=>$v}{if isset($get.type) and $k eq $get.type}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">上传时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择上传时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>

View File

@ -1,32 +0,0 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/iconfont.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/extra/style.css?at={:date('md')}">
{block name="style"}{/block}
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
<script src="{:url('admin/api.plugs/script',[],false,false)}"></script>
</head>
<body class="layui-layout-body">
{block name='body'}
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
<div class="layui-body think-bg-white margin-0 padding-0" style="top:0">{block name='content'}{/block}</div>
</div>
{/block}
<script src="__ROOT__/static/plugs/layui/layui.js"></script>
<script src="__ROOT__/static/plugs/require/require.js"></script>
<script src="__ROOT__/static/admin.js"></script>
<script src="__ROOT__/static/extra/script.js"></script>
{block name='script'}{/block}
</body>
</html>

View File

@ -1,50 +0,0 @@
<div class="layui-side">
<a class="layui-side-target" data-target-menu-type></a>
<a class="layui-logo layui-elip" href="{:sysuri('@')}" title="{:sysconf('app_name')}">
<span class="headimg headimg-no headimg-xs" data-lazy-src="{:sysconf('site_icon')}"></span>
<span class="headtxt">{:sysconf('app_name')} {if sysconf('app_version')}<sup>{:sysconf('app_version')}</sup>{/if}</span>
</a>
<div class="layui-side-scroll">
<div class="layui-side-icon">
{foreach $menus as $one}
<div>
<a data-menu-node="m-{$one.id}" data-open="{$one.url}" data-target-tips="{$one.title|default=''}">
{notempty name='one.icon'}<i class="{$one.icon|default=''}"></i>{/notempty}
<span>{$one.title|default=''}</span>
</a>
</div>
{/foreach}
</div>
<div class="layui-side-tree">
{foreach $menus as $one}{notempty name='one.sub'}
<ul class="layui-nav layui-nav-tree layui-hide" data-menu-layout="m-{$one.id}">
{foreach $one.sub as $two}{empty name='two.sub'}
<li class="layui-nav-item">
<a data-target-tips="{$two.title}" data-menu-node="m-{$one.id}-{$two.id}" data-open="{$two.url}">
<span class='nav-icon {$two.icon|default="layui-icon layui-icon-senior"}'></span>
<span class="nav-text">{$two.title|default=''}</span>
</a>
</li>
{else}
<li class="layui-nav-item" data-submenu-layout='m-{$one.id}-{$two.id}'>
<a data-target-tips="{$two.title}">
<span class='nav-icon layui-hide {$two.icon|default="layui-icon layui-icon-triangle-d"}'></span>
<span class="nav-text">{$two.title|default=''}</span>
</a>
<dl class="layui-nav-child">
{foreach $two.sub as $thr}
<dd>
<a data-target-tips="{$thr.title}" data-open="{$thr.url}" data-menu-node="m-{$one.id}-{$two.id}-{$thr.id}">
<span class='nav-icon {$thr.icon|default="layui-icon layui-icon-senior"}'></span>
<span class="nav-text">{$thr.title|default=''}</span>
</a>
</dd>
{/foreach}
</dl>
</li>
{/empty}{/foreach}
</ul>
{/notempty}{/foreach}
</div>
</div>
</div>

View File

@ -1,44 +0,0 @@
<div class="layui-header">
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item" lay-unselect>
<a class="text-center" data-target-menu-type>
<i class="layui-icon layui-icon-spread-left"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
<a class="layui-logo-hide layui-elip" href="{:sysuri('@')}" title="{:sysconf('app_name')}">
<span class="headimg headimg-no headimg-xs" data-lazy-src="{:sysconf('site_icon')}"></span>
</a>
</li>
{foreach $menus as $one}
<li class="layui-nav-item">
<a data-menu-node="m-{$one.id}" data-open="{$one.url}"><span>{$one.title|default=''}</span></a>
</li>
{/foreach}
</ul>
<ul class="layui-nav layui-layout-right">
<li lay-unselect class="layui-nav-item"><a data-reload><i class="layui-icon layui-icon-refresh-3"></i></a></li>
{if session('user.username')}
<li class="layui-nav-item">
<dl class="layui-nav-child">
<dd lay-unselect><a data-modal="{:sysuri('admin/index/info',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-set-fill"></i> 基本资料</a></dd>
<dd lay-unselect><a data-modal="{:sysuri('admin/index/pass',['id'=>session('user.id')])}"><i class="layui-icon layui-icon-component"></i> 安全设置</a></dd>
{if isset($super) and $super}
<dd lay-unselect><a data-load="{:sysuri('admin/api.system/push')}"><i class="layui-icon layui-icon-template-1"></i> 缓存加速</a></dd>
<dd lay-unselect><a data-load="{:sysuri('admin/api.system/clear')}"><i class="layui-icon layui-icon-fonts-clear"></i> 清理缓存</a></dd>
{/if}
<dd lay-unselect><a data-width="520px" data-modal="{:sysuri('admin/index/theme')}"><i class="layui-icon layui-icon-theme"></i> 配色方案</a></dd>
<dd lay-unselect><a data-load="{:sysuri('admin/login/out')}" data-confirm="确定要退出登录吗?"><i class="layui-icon layui-icon-release"></i> 退出登录</a></dd>
</dl>
<a class="layui-elip">
<span class="headimg" data-lazy-src="{:htmlentities(session('user.headimg'))}"></span>
<span>{:htmlentities(session('user.nickname')?:session('user.username'))}</span>
</a>
</li>
{else}
<li class="layui-nav-item">
<a data-href="{:sysuri('admin/login/index')}"><i class="layui-icon layui-icon-username"></i> 立即登录</a>
</li>
{/if}
</ul>
</div>

View File

@ -1,62 +0,0 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/iconfont.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/extra/style.css?at={:date('md')}">
{block name="style"}{/block}
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
<script src="{:url('admin/api.plugs/script',[],false,false)}"></script>
</head>
<body class="layui-layout-body layui-layout-theme-{$theme|default='default'}">
{block name='body'}
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
<!-- 左则菜单 开始 -->
{include file="index/index-left"}
<!-- 左则菜单 结束 -->
<!-- 顶部菜单 开始 -->
{include file='index/index-top'}
<!-- 顶部菜单 结束 -->
<!-- 主体内容 开始 -->
<div class="layui-body">
<div class="think-page-body">
{block name='content'}{/block}
</div>
<!-- 页面加载动画 -->
<div class="think-page-loader layui-hide">
<div class="loader"></div>
</div>
</div>
<!-- 主体内容 结束 -->
</div>
<!-- 加载动画 开始 -->
<div class="think-page-loader">
<div class="loader"></div>
</div>
<!-- 加载动画 结束 -->
{/block}
<script src="__ROOT__/static/plugs/layui/layui.js"></script>
<script src="__ROOT__/static/plugs/require/require.js"></script>
<script src="__ROOT__/static/admin.js"></script>
<script src="__ROOT__/static/extra/script.js"></script>
{block name='script'}{/block}
</body>
</html>

View File

@ -1,36 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" id="theme">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item margin-bottom-5 label-required-prev">
<div class="help-label"><b>后台配色方案</b>Theme Style</div>
<div class="layui-textarea think-bg-gray" style="min-height:unset">
{foreach $themes as $k=>$v}
<label class="think-radio">
{if isset($theme) and $theme eq $k}
<input name="site_theme" type="radio" value="{$k}" lay-ignore checked> {$v}
{else}
<input name="site_theme" type="radio" value="{$k}" lay-ignore> {$v}
{/if}
</label>
{/foreach}
</div>
<p class="help-block">切换配色方案,需要保存成功后配色方案才会永久生效,下次登录也会有效哦 ~</p>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" type="submit">保存配置</button>
<button class="layui-btn layui-btn-danger" type='button' data-close>取消修改</button>
</div>
</form>
<script>
$('form#theme input[name=site_theme]').on('click', function () {
var alls = '', that = this, prox = 'layui-layout-theme-', curt = prox + that.value;
$('form#theme input[name=site_theme]').map(function () {
if (this.value !== that.value) alls += ' ' + prox + this.value;
});
$('.layui-layout-body').removeClass(alls).addClass(curt)
});
</script>

View File

@ -1,57 +0,0 @@
{extend name="index/index"}
{block name='style'}
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<script>if (location.href.indexOf('#') > -1) location.replace(location.href.split('#')[0])</script>
<link rel="stylesheet" href="__ROOT__/static/theme/css/login.css">
{/block}
{block name="body"}
<div class="login-container" {$loginStyle|raw}>
<div class="header notselect layui-hide-xs">
<a href="{:url('@')}" class="title">{:sysconf('app_name')}<span>{:sysconf('app_version')}</span></a>
{notempty name='developMode'}
<a class="pull-right layui-anim layui-anim-fadein" target="_blank" href='https://gitee.com/zoujingli/ThinkAdmin'>
<img src='https://gitee.com/zoujingli/ThinkAdmin/widgets/widget_1.svg' alt='Fork me on Gitee'>
</a>
{/notempty}
</div>
<form data-login-form onsubmit="return false" method="post" class="layui-anim layui-anim-upbit" autocomplete="off">
<h2 class="notselect">{:sysconf('login_name')?:'系统管理'}</h2>
<ul>
<li class="username">
<label class="label-required-null">
<i class="layui-icon layui-icon-username"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="username" autofocus autocomplete="off" placeholder="登录账号" title="请输入登录账号">
</label>
</li>
<li class="password">
<label class="label-required-null">
<i class="layui-icon layui-icon-password"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="password" maxlength="32" type="password" autocomplete="off" placeholder="登录密码" title="请输入登录密码">
</label>
</li>
<li class="verify layui-hide">
<label class="inline-block relative label-required-null">
<i class="layui-icon layui-icon-picture-fine"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="verify" maxlength="4" autocomplete="off" placeholder="验证码" title="请输入验证码">
</label>
<label data-captcha="{:url('admin/login/captcha',[],false)}" data-field-verify="verify" data-field-uniqid="uniqid" data-captcha-type="{$captchaType}" data-captcha-token="{$captchaToken}"></label>
</li>
<li class="text-center padding-top-20">
<button type="submit" class="layui-btn layui-disabled full-width" data-form-loaded="立即登入">正在载入</button>
</li>
</ul>
</form>
<div class="footer notselect">
<p class="layui-hide-xs">推荐使用 <a target="_blank" href="https://www.google.cn/chrome">Google Chrome</a><a target="_blank" href="https://www.microsoft.com/zh-cn/edge#platform">Microsoft Edge</a> 浏览器访问</p>
{:sysconf('site_copy')}
{if sysconf('beian')}<span class="padding-5">|</span><a target="_blank" href="https://beian.miit.gov.cn/">{:sysconf('beian')}</a>{/if}
{if sysconf('miitbeian')}<span class="padding-5">|</span><a target="_blank" href="https://beian.miit.gov.cn/">{:sysconf('miitbeian')}</a>{/if}
</div>
</div>
{/block}
{block name='script'}
<script src="__ROOT__/static/login.js"></script>
{/block}

View File

@ -1,18 +0,0 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}
{notempty name='title'}
<div class="layui-card-header">
<span class="layui-icon font-s10 color-desc margin-right-5">&#xe65b;</span>{$title|default=''}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
{/block}
<div class="layui-card-line"></div>
<div class="layui-card-body">
<div class="layui-card-html">
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

View File

@ -1,97 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="MenuTable">
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label label-required-next">上级菜单</label>
<div class="layui-input-block">
<select name='pid' class='layui-select' lay-search>
{foreach $menus as $menu}{eq name='menu.id' value='$vo.pid|default=0'}
<option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
{else}
<option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
{/eq}{/foreach}
</select>
<p class="help-block"><b>必选</b>,请选择上级菜单或顶级菜单 ( 目前最多支持三级菜单 )</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单名称</label>
<div class="layui-input-block">
<input name="title" value='{$vo.title|default=""}' required placeholder="请输入菜单名称" class="layui-input">
<p class="help-block"><b>必选</b>,请填写菜单名称 ( 如:系统管理 ),建议字符不要太长,一般 4-6 个汉字</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单链接</label>
<div class="layui-input-block">
<input onblur="this.value=this.value === ''?'#':this.value" name="url" required placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input">
<p class="help-block">
<b>必选</b>,请填写链接地址或选择系统节点 ( 如https://domain.com/admin/user/index.html 或 admin/user/index )
<br>当填写链接地址时,以下面的 “权限节点” 来判断菜单自动隐藏或显示,注意未填写 “权限节点” 时将不会隐藏该菜单哦
</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">链接参数</label>
<div class="layui-input-block">
<input name="params" placeholder="请输入链接参数" value="{$vo.params|default=''}" class="layui-input">
<p class="help-block"><b>可选</b>,设置菜单链接的 GET 访问参数 ( 如name=1&age=3 )</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">权限节点</label>
<div class="layui-input-block">
<input name="node" placeholder="请输入权限节点" value="{$vo.node|default=''}" class="layui-input">
<p class="help-block"><b>可选</b>,请填写系统权限节点 ( 如admin/user/index ),未填写时默认解释"菜单链接"判断是否拥有访问权限;</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">菜单图标</label>
<div class="layui-input-block">
<div class="layui-input-inline">
<input placeholder="请输入或选择图标" name="icon" value='{$vo.icon|default=""}' class="layui-input">
</div>
<span style="padding:0 12px;min-width:45px" class='layui-btn layui-btn-primary'>
<i style="font-size:1.2em;margin:0;float:none" class='{$vo.icon|default=""}'></i>
</span>
<button data-icon='icon' type='button' class='layui-btn layui-btn-primary'>选择图标</button>
<p class="help-block"><b>可选</b>,设置菜单选项前置图标,目前支持 layui 字体图标及 iconfont 定制字体图标。</p>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>
<script>
require(['jquery.autocompleter'], function () {
$('[name="icon"]').on('change', function () {
$(this).parent().next().find('i').get(0).className = this.value
}), $('input[name=url]').autocompleter({
limit: 6, highlightMatches: true, template: '{{ label }} <span> {{ title }} </span>', callback: function (node) {
$('input[name=node]').val(node);
}, source: (function (subjects, data) {
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
return data;
})(JSON.parse('{$nodes|raw|json_encode}'), [])
}), $('input[name=node]').autocompleter({
limit: 5, highlightMatches: true, template: '{{ label }} <span> {{ title }} </span>', source: (function (subjects, data) {
for (var i in subjects) data.push({value: subjects[i].node, label: subjects[i].node, title: subjects[i].title});
return data;
})(JSON.parse('{$auths|raw|json_encode}'), [])
});
});
</script>

View File

@ -1,123 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if $type eq 'index' and auth("add")}-->
<button data-modal='{:url("add")}' data-table-id="MenuTable" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
<!--{/if}-->
<!--{if $type eq 'index' and auth("state")}-->
<button data-action='{:url("state")}' data-table-id="MenuTable" data-rule="id#{sps};status#0" class='layui-btn layui-btn-sm layui-btn-primary'>禁用菜单</button>
<!--{/if}-->
<!--{if $type eq 'recycle' and auth("state")}-->
<button data-action='{:url("state")}' data-table-id="MenuTable" data-rule="id#{spp};status#1" class='layui-btn layui-btn-sm layui-btn-primary'>激活菜单</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach ['index'=>'系统菜单','recycle'=>'回 收 站'] as $k=>$v}
{if isset($type) and $type eq $k}
<li class="layui-this" data-open="{:url('index')}?type={$k}">{$v}</li>
{else}
<li data-open="{:url('index')}?type={$k}">{$v}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
<table id="MenuTable" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
</div>
<script>
$(function () {
$('#MenuTable').layTable({
even: true, height: 'full', page: false,
sort: {field: 'sort desc,id', type: 'asc'},
where: {type: '{$type|default="index"}'},
filter: function (items) {
var type = this.where.type;
return items.filter(function (item) {
return !(type === 'index' && item.status === 0);
});
},
cols: [[
{checkbox: true, field: 'sps'},
{field: 'sort', title: '排序权重', width: 100, align: 'center', templet: '#SortInputTpl'},
{
field: 'icon', title: '图 标', width: 80, align: 'center', templet: function (d) {
return layui.laytpl('<i class="{{d.icon}} font-s18"></i>').render(d);
}
},
{
field: 'title', title: '菜单名称', minWidth: 220, templet: function (d) {
return layui.laytpl('<span class="color-desc">{{d.spl}}</span>{{d.title}}').render(d);
}
},
{field: 'url', title: '跳转链接', minWidth: 200},
{field: 'status', title: '菜单状态', minWidth: 120, align: 'center', templet: '#StatusSwitchTpl'},
// {field: 'create_at', title: '创建时间', minWidth: 170, align: 'center'},
{toolbar: '#toolbar', title: '操作面板', minWidth: 150, align: 'center', fixed: 'right'},
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (object) {
object.data = {status: object.elem.checked > 0 ? 1 : 0};
object.data.id = object.value.split('|')[object.data.status] || object.value;
$.form.load("{:url('state')}", object.data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#MenuTable').trigger('reload');
}); else {
$('#MenuTable').trigger('reload');
}
return false;
}, false);
});
});
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
{{# if( "{$type|default='index'}"==='index' || (d.spc<1 || d.status<1)){ }}
<input type="checkbox" value="{{d.sps}}|{{d.spp}}" lay-text="已激活|已禁用" lay-filter="StatusSwitch" lay-skin="switch" {{-d.status>0?'checked':''}}>
{{# }else{ }}
{{-d.status ? '<b class="color-green">已激活</b>' : '<b class="color-red">已禁用</b>'}}
{{# } }}
<!--{else}-->
{{-d.status ? '<b class="color-green">已激活</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<!-- 操控面板的模板 -->
<script type="text/html" id="toolbar">
<!-- {if isset($type) and $type eq 'index'} -->
<!-- {if auth('add')} -->
{{# if(d.spt<2){ }}
<a class="layui-btn layui-btn-sm layui-btn-primary" data-title="添加系统菜单" data-modal='{:url("add")}?pid={{d.id}}'>添 加</a>
{{# }else{ }}
<a class="layui-btn layui-btn-sm layui-btn-disabled">添 加</a>
{{# } }}
<!-- {/if} -->
{if auth('edit')}
<a class="layui-btn layui-btn-sm" data-event-dbclick data-title="编辑系统菜单" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
{/if}
<!-- {else} -->
{if auth('remove')}
{{# if( (d.spc<1 || d.status<1)){ }}
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除菜单吗?" data-action="{:url('remove')}" data-value="id#{{d.sps}}">删 除</a>
{{# }else{ }}
<a class="layui-btn layui-btn-disabled layui-btn-sm">删 除</a>
{{# } }}
{/if}
<!-- {/if} -->
</script>
{/block}

View File

@ -1,44 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card">
<div class="layui-card-body padding-left-40">
<div class="layui-textarea border-0 font-s14 layui-bg-gray padding-top-20 padding-left-20">
<div class="layui-row margin-bottom-15">
<div class="layui-col-xs6">模块名称:<b class="color-green">{$module.name}</b></div>
<div class="layui-col-xs6">开发作者:<b class="color-green">{$module.author}</b></div>
</div>
<div class="layui-row margin-bottom-15">
<div class="layui-col-xs6">最新版本:<b class="color-green">{$module.version}</b></div>
<div class="layui-col-xs6">{if isset($current.version)}已安装版本:<b class="color-green">{$current.version}</b>{/if}</div>
</div>
<div class="margin-bottom-15">模块描述:{$module.content}</div>
</div>
<ul class="layui-timeline margin-top-30 margin-bottom-30" style="max-height:400px;overflow:auto">
{foreach $module.change as $version=>$change}
<li class="layui-timeline-item">
{if isset($current.version) and $current.version eq $version}
<i class="layui-icon layui-timeline-axis">&#xe756;</i>
{else}
<i class="layui-icon layui-timeline-axis">&#xe63f;</i>
{/if}
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">
版本号 {$version} <span class="margin-left-10 font-s13 color-desc">{$change.version|default=''}</span>
</h3>
<div data-marked>
{$change.content|default=''|raw}
</div>
</div>
</li>
{/foreach}
<li class="layui-timeline-item"></li>
</ul>
</div>
<script>
require(['marked'], function (marked) {
$('[data-marked]').map(function () {
if (this.marked) return; else this.marked = true;
this.innerHTML = marked.parse(this.innerHTML);
});
});
</script>
</form>

View File

@ -1,42 +0,0 @@
{extend name='main'}
{block name="content"}
<div class="think-box-shadow">
<table class="layui-table margin-top-15" lay-skin="line">
{notempty name='modules'}
<thead>
<tr>
<th class='text-left nowrap'>模块名称</th>
<th class='text-left nowrap'>模块描述</th>
<th class='text-left nowrap'>当前版本</th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $modules as $key=>$vo}
<tr>
<td class='text-left nowrap'>{$vo.name}</td>
<td class='text-left nowrap'>{$vo.content}</td>
<td class='text-left nowrap'>
<div class="inline-block pointer" data-title="查看模块版本" data-modal="{:url('change')}?name={$vo.name}">
{if isset($vo.local)} {$vo.local.version}
{if $vo.version > $vo.local.version}
<span class="color-red margin-left-5">{$vo.version}</span>
{else}
<span class="color-desc margin-left-5">{$vo.type_desc}</span>
{/if}
{else}<span class="color-desc margin-left-5">{$vo.type_desc}</span>{/if}
</div>
</td>
<td class="text-left">
{if $vo.type_code eq 1} <a class="layui-btn layui-btn-xs" data-action="{:url('install')}" data-value="name#{$vo.name}">安 装</a>{/if}
{if $vo.type_code eq 2} <a class="layui-btn layui-btn-xs" data-action="{:url('install')}" data-value="name#{$vo.name}">更 新</a>{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='modules'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

View File

@ -1,58 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务编号</label>
<div class="layui-input-inline">
<input name="code" value="{$get.code|default=''}" placeholder="请输入任务编号" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务名称</label>
<div class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入任务名称" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务指令</label>
<div class="layui-input-inline">
<input name="command" value="{$get.command|default=''}" placeholder="请输入任务指令" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务状态</label>
<div class="layui-input-inline">
<select name="status" class="layui-select">
{foreach [''=>'-- 全部状态 --','1'=>'待处理','2'=>'处理中','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
{if isset($get.status) and $get.status eq $k}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">计划时间</label>
<div class="layui-input-inline">
<input data-date-range name="exec_time" value="{$get.exec_time|default=''}" placeholder="请选择计划时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">执行时间</label>
<div class="layui-input-inline">
<input data-date-range name="enter_time" value="{$get.enter_time|default=''}" placeholder="请选择执行时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>

View File

@ -1,47 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if auth("remove")}-->
<button data-table-id="OplogTable" data-action='{:url("remove")}' data-rule="id#{id}" data-confirm="确定要删除选中的日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
<!--{if auth("clear")}-->
<button data-table-id="OplogTable" data-load='{:url("clear")}' data-confirm="确定要清空所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清空日志</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='oplog/index_search'}
<table id="OplogTable" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
$('#OplogTable').layTable({
even: true, height: 'full',
sort: {field: 'id', type: 'desc'},
cols: [[
{checkbox: true},
{field: 'id', title: 'ID', width: 80, sort: true, align: 'center'},
{field: 'username', title: '操作账号', minWidth: 100, sort: true, align: 'center'},
{field: 'node', title: '操作节点', minWidth: 120},
{field: 'action', title: '操作行为', minWidth: 120},
{field: 'content', title: '操作描述', minWidth: 150},
{field: 'geoip', title: '访问地址', minWidth: 100},
{field: 'geoisp', title: '网络服务商', minWidth: 100},
{field: 'create_at', title: '操作时间', minWidth: 170, align: 'center', sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 80, fixed: 'right'}
]]
});
});
</script>
<script type="text/html" id="toolbar">
<!--{if auth('remove')}-->
<a data-action='{:url("remove")}' data-value="id#{{d.id}}" data-confirm="确认要删除这条记录吗?" class="layui-btn layui-btn-sm layui-btn-danger">删 除</a>
<!--{/if}-->
</script>
{/block}

View File

@ -1,129 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作账号</label>
<div class="layui-input-inline">
<select name='username' lay-search class="layui-select">
<option value=''>-- 全部账号 --</option>
{foreach $users as $user}{if $user eq input('get.username')}
<option selected value="{$user}">{$user}</option>
{else}
<option value="{$user}">{$user}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作行为</label>
<div class="layui-input-inline">
<select name="action" lay-search class="layui-select">
<option value=''>-- 全部行为 --</option>
{foreach $actions as $action}{if $action eq input('get.action')}
<option selected value="{$action}">{$action}</option>
{else}
<option value="{$action}">{$action}</option>
{/if}{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作节点</label>
<label class="layui-input-inline">
<input name="node" value="{$get.node|default=''}" placeholder="请输入操作内容" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作描述</label>
<label class="layui-input-inline">
<input name="content" value="{$get.content|default=''}" placeholder="请输入操作内容" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">访问地址</label>
<label class="layui-input-inline">
<input name="geoip" value="{$get.geoip|default=''}" placeholder="请输入访问地址" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">操作时间</label>
<label class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择操作时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<button type="submit" class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
<button type="button" data-form-export="{:url('index')}?type={$type|default=''}" class="layui-btn layui-btn-primary">
<i class="layui-icon layui-icon-export"></i> 导 出
</button>
</div>
</form>
</fieldset>
<script>
require(['excel'], function (excel) {
excel.bind(function (data) {
// 设置表格内容
data.forEach(function (item, index) {
data[index] = [item.id, item.username, item.node, item.geoip, item.geoisp, item.action, item.content, item.create_at];
});
// 设置表头内容
data.unshift(['ID', '操作账号', '访问节点', '访问IP地址', '访问地理区域', '访问操作', '操作内容', '操作时间']);
// 自动计算列序号
var lastCol = layui.excel.numToTitle(data[0].length || 0);
// 设置表头样式
layui.excel.setExportCellStyle(data, 'A1:' + lastCol + '1', {
s: {
font: {sz: 12, bold: true, color: {rgb: "FFFFFF"}, name: '微软雅黑', shadow: true},
fill: {bgColor: {indexed: 64}, fgColor: {rgb: "5FB878"}},
alignment: {vertical: 'center', horizontal: 'center'}
}
});
// 设置内容样式
var style1 = {
font: {sz: 10, shadow: true, name: '微软雅黑'},
fill: {bgColor: {indexed: 64}, fgColor: {rgb: "EAEAEA"}},
alignment: {vertical: 'center', horizontal: 'center'}
}, style2 = {
font: {sz: 10, shadow: true, name: '微软雅黑'},
fill: {bgColor: {indexed: 64}, fgColor: {rgb: "FFFFFF"}},
alignment: {vertical: 'center', horizontal: 'center'}
};
// 动态应用样式
layui.excel.setExportCellStyle(data, 'A2:' + lastCol + data.length, {s: style1}, function (raw, cell, list, conf, rows, cols) {
// @var raw 原有单元格数据
// @var cell 新的单元格数据
// @var list 所在行数据列表
// @var conf 当前样式配置
// @var rows 当前行的标号
// @var cols 当前列的标号
return (rows % 2 === 0) ? cell : (Object.assign({}, cell, {s: style2}));
});
// 设置表格行宽高,需要设置最后的行或列宽高,否则部分不生效
var rowsC = {1: 33}, colsC = {A: 60, B: 80, C: 99, E: 80, G: 120};
rowsC[data.length] = 28, colsC[lastCol] = 160;
this.options.extend = {
'!rows': layui.excel.makeRowConfig(rowsC, 28), // 设置每行高度,默认 33
'!cols': layui.excel.makeColConfig(colsC, 99), // 设置每行宽度,默认 99
};
// 其他更多样式,可以配置 this.options.extend 参数,每次执行 bind 会被重置
// 在线文档http://excel.wj2015.com/_book/docs/%E5%87%BD%E6%95%B0%E5%88%97%E8%A1%A8/%E6%A0%B7%E5%BC%8F%E8%AE%BE%E7%BD%AE%E7%9B%B8%E5%85%B3%E5%87%BD%E6%95%B0.html
return data;
}, '操作日志' + layui.util.toDateString(Date.now(), '_yyyyMMdd_HHmmss'));
});
</script>

View File

@ -1,117 +0,0 @@
{extend name='table'}
{block name="button"}
<!--{if isset($super) and $super}-->
<a data-table-id="QueueTable" class="layui-btn layui-btn-sm layui-btn-primary" data-queue="{:url('admin/api.plugs/optimize')}">优化数据库</a>
<!--{/if}-->
<!--{if isset($super) and $super and $iswin}-->
<button data-load='{:url("admin/api.queue/start")}' class='layui-btn layui-btn-sm layui-btn-primary'>开启服务</button>
<button data-load='{:url("admin/api.queue/stop")}' class='layui-btn layui-btn-sm layui-btn-primary'>关闭服务</button>
<!--{/if}-->
<!--{if auth("clean")}-->
<button data-table-id="QueueTable" data-queue='{:url("clean")}' class='layui-btn layui-btn-sm layui-btn-primary'>定时清理</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-table-id="QueueTable" data-action='{:url("remove")}' data-rule="id#{id}" data-confirm="确定批量删除记录吗?" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</button>
<!--{/if}-->
{/block}
{block name="content"}
<div class="think-box-notify">
<!--{if isset($super) and $super}-->
<b>服务状态:</b><b class="margin-right-5" data-queue-message><span class="color-desc">检查中</span></b>
<b data-tips-text="点击可复制【服务启动指令】" class="layui-icon pointer margin-right-20" data-copy="{$command|default=''}">&#xe60e;</b>
<script>$('[data-queue-message]').load('{:sysuri("admin/api.queue/status")}');</script>
<!--{/if}-->
<b>任务统计:</b>待处理 <b class="color-text" data-extra="pre">{$total.pre|default=0}</b> 个任务,处理中 <b class="color-blue" data-extra="dos">{$total.dos|default=0}</b> 个任务,已完成 <b class="color-green" data-extra="oks">{$total.oks|default=0}</b> 个任务,已失败 <b class="color-red" data-extra="ers">{$total.ers|default=0}</b> 个任务。
</div>
<div class="think-box-shadow">
{include file='queue/index_search'}
<table id="QueueTable" data-line="2" data-url="{:sysuri()}" data-target-search="form.form-search"></table>
</div>
{/block}
{block name='script'}
<script>
$(function () {
$('#QueueTable').layTable({
even: true, height: 'full',
sort: {field: 'loops_time desc,id', type: 'desc'},
// 扩展数据处理,需要返回原 items 数据
filter: function (items, result) {
return result && result.extra && $('[data-extra]').map(function () {
this.innerHTML = result.extra[this.dataset.extra] || 0;
}), items;
},
cols: [[
{checkbox: true, fixed: 'left'},
{
field: 'id', title: '任务名称', width: '25%', sort: true, templet: function (d) {
if (d.loops_time > 0) {
d.one = '<span class="layui-badge think-bg-blue"></span>';
} else {
d.one = '<span class="layui-badge think-bg-red"></span>';
}
if (d.rscript === 1) {
d.two = '<span class="layui-badge layui-bg-green"></span>';
} else {
d.two = '<span class="layui-badge think-bg-violet"></span>';
}
return laytpl('{{-d.one}}任务编号:<b>{{d.code}}</b><br>{{-d.two}}任务名称:{{d.title}}').render(d);
}
},
{
field: 'exec_time', title: '任务计划', width: '25%', templet: function (d) {
d.html = '执行指令:' + d.command + '<br>计划执行:' + d.exec_time;
if (d.loops_time > 0) {
return d.html + ' ( 每 <b class="color-blue">' + d.loops_time + '</b> 秒 ) ';
} else {
return d.html + ' <span class="color-desc">( 单次任务 )</span> ';
}
}
},
{
field: 'loops_time', title: '执行状态', width: '30%', templet: function (d) {
d.html = ([
'<span class="pull-left layui-badge layui-badge-middle layui-bg-gray">未知</span>',
'<span class="pull-left layui-badge layui-badge-middle layui-bg-black">等待</span>',
'<span class="pull-left layui-badge layui-badge-middle layui-bg-blue">执行</span>',
'<span class="pull-left layui-badge layui-badge-middle layui-bg-green">完成</span>',
'<span class="pull-left layui-badge layui-badge-middle layui-bg-red">失败</span>',
][d.status] || '') + '执行时间:';
d.enter_time = d.enter_time || '', d.outer_time = d.outer_time || '0.0000';
if (d.enter_time.length > 12) {
d.html += d.enter_time.substring(12) + '<span class="color-desc"> ( 耗时 ' + d.outer_time + ' ) </span>';
d.html += ' 已执行 <b class="color-blue">' + (d.attempts || 0) + '</b> 次';
} else {
d.html += '<span class="color-desc">任务未执行</span>'
}
return d.html + '<br>执行结果:<span class="color-blue">' + (d.exec_desc || '<span class="color-desc">未获取到执行结果</span>') + '</span>';
}
},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 210, fixed: 'right'}
]]
});
});
</script>
<script type="text/html" id="toolbar">
<!--{if auth('redo')}-->
{{# if(d.status===4||d.status===3){ }}
<a class="layui-btn layui-btn-sm" data-confirm="确定要重置该任务吗?" data-queue="{:url('redo')}?code={{d.code}}">重 置</a>
{{# }else{ }}
<a class="layui-btn layui-btn-sm layui-btn-disabled">重 置</a>
{{# } }}
<!--{/if}-->
<!--{if auth('remove')}-->
<a class='layui-btn layui-btn-sm layui-btn-danger' data-confirm="确定要删除该任务吗?" data-action='{:url("remove")}' data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
<a class='layui-btn layui-btn-sm layui-btn-normal' onclick="$.loadQueue('{{d.code}}',false,this)">日 志</a>
</script>
{/block}

View File

@ -1,59 +0,0 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">编号名称</label>
<label class="layui-input-inline">
<input name="title" value="{$get.title|default=''}" placeholder="请输入名称或编号" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务指令</label>
<label class="layui-input-inline">
<input name="command" value="{$get.command|default=''}" placeholder="请输入任务指令" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">任务状态</label>
<label class="layui-input-inline">
<select name="status" class="layui-select">
<option value=''>-- 全部任务 --</option>
{foreach ['1'=>'等待处理','2'=>'正在处理','3'=>'处理完成','4'=>'处理失败'] as $k=>$v}
{if isset($get.status) and $get.status eq $k}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/if}{/foreach}
</select>
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">计划时间</label>
<label class="layui-input-inline">
<input data-date-range name="exec_time" value="{$get.exec_time|default=''}" placeholder="请选择计划时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">执行时间</label>
<label class="layui-input-inline">
<input data-date-range name="enter_time" value="{$get.enter_time|default=''}" placeholder="请选择执行时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">创建时间</label>
<label class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>
</fieldset>

View File

@ -1,18 +0,0 @@
<div class="layui-card">
{block name='style'}{/block}
{block name='header'}
{notempty name='title'}
<div class="layui-card-header">
<span class="layui-icon font-s10 color-desc margin-right-5">&#xe65b;</span>{$title|default=''}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
{/block}
<div class="layui-card-line"></div>
<div class="layui-card-body">
<div class="layui-card-table">
{block name='content'}{/block}
</div>
</div>
{block name='script'}{/block}
</div>

View File

@ -1,114 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="UserTable">
<div class="layui-card-body padding-left-40">
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">用户账号</b></legend>
<div class="layui-row layui-col-space15">
<div class="layui-col-xs2 text-center padding-top-15">
<input type="hidden" data-cut-width="500" data-cut-height="500" data-max-width="500" data-max-height="500" name="headimg" value="{$vo.headimg|default=''}">
<script>$('[name=headimg]').uploadOneImage();</script>
</div>
<div class="layui-col-xs5">
<label class="block relative">
<span class="help-label"><b>登录账号</b>User Name</span>
{if isset($vo) and isset($vo.username)}
<input disabled value='{$vo.username|default=""}' required class="layui-input think-bg-gray">
{else}
<input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入登录账号" class="layui-input">
{/if}
<span class="help-block">登录账号不能重复并且创建后不能再次修改哦。</span>
</label>
</div>
<div class="layui-col-xs5">
<label class="block relative">
<span class="help-label"><b>用户名称</b>Nick Name</span>
<input name="nickname" value='{$vo.nickname|default=""}' required placeholder="请输入用户名称" class="layui-input">
<span class="help-block">用于区分用户数据的用户名称,请尽量不要重复。</span>
</label>
</div>
</div>
</fieldset>
{if !empty($bases) || !empty($authorizes)}
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">用户权限</b></legend>
{if !empty($bases)}
<div class="layui-form-item">
<div class="help-label"><b>角色身份</b>Role Identity</div>
<div class="layui-textarea help-checks">
{foreach $bases as $base}
<label class="think-checkbox">
{if isset($vo.usertype) and $vo.usertype eq $base.code}
<input type="radio" checked name="usertype" value="{$base.code}" lay-ignore>{$base.name}
{else}
<input type="radio" name="usertype" value="{$base.code}" lay-ignore>{$base.name}
{/if}
</label>
{/foreach}
</div>
</div>
{/if}
{if !empty($authorizes)}
<div class="layui-form-item">
<div class="help-label"><b>访问权限</b>Role Permission</div>
<div class="layui-textarea help-checks">
{if isset($vo.username) and $vo.username eq $superName}
<span class="color-desc padding-left-5">超级用户拥所有访问权限,不需要配置权限。</span>
{else}{foreach $authorizes as $authorize}
<label class="think-checkbox">
{if in_array($authorize.id, $vo.authorize)}
<input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{else}
<input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore>{$authorize.title}
{/if}
</label>
{/foreach}{/if}
</div>
</div>
{/if}
</fieldset>
{/if}
<fieldset class="layui-bg-gray">
<legend><b class="layui-badge think-bg-violet">用户资料</b></legend>
<div class="layui-row layui-col-space15">
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系邮箱</b>Contact Email</span>
<input name="contact_mail" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" value='{$vo.contact_mail|default=""}' placeholder="请输入联系电子邮箱" class="layui-input">
<span class="color-desc">可选,请填写用户常用的电子邮箱</span>
</label>
</div>
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系手机</b>Contact Mobile</span>
<input type="tel" maxlength="11" name="contact_phone" value='{$vo.contact_phone|default=""}' pattern="^1[3-9][0-9]{9}$" placeholder="请输入用户联系手机" class="layui-input">
<span class="color-desc">可选,请填写用户常用的联系手机号</span>
</label>
</div>
<div class="layui-col-xs4">
<label class="relative block">
<span class="help-label"><b>联系QQ</b>Contact QQ</span>
<input name="contact_qq" pattern="^\d{6,}$" value='{$vo.contact_qq|default=""}' placeholder="请输入常用的联系QQ" class="layui-input">
<span class="color-desc">可选,请填写用户常用的联系QQ号</span>
</label>
</div>
</div>
<label class="layui-form-item block relative margin-top-10">
<span class="help-label"><b>用户描述</b>User Remark</span>
<textarea placeholder="请输入用户描述" class="layui-textarea" name="describe">{$vo.describe|default=""}</textarea>
</label>
</fieldset>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,116 +0,0 @@
{extend name='table'}
{block name="button"}
{if isset($type) and $type eq 'index'}
<!--{if auth("add")}-->
<button data-modal='{:url("add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
<!--{/if}-->
<!--{if auth("state")}-->
<a data-confirm="确定要启用该用户吗?" data-table-id="UserTable" data-action="{:url('state')}" data-rule="id#{id};status#0" class='layui-btn layui-btn-sm layui-btn-primary'>批量禁用</a>
<!--{/if}-->
{else}
<!--{if auth("state")}-->
<a data-confirm="确定要恢复这些账号吗?" data-table-id="UserTable" data-action="{:url('state')}" data-rule="id#{id};status#1" class='layui-btn layui-btn-sm layui-btn-primary'>批量恢复</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a data-confirm="确定永久删除这些账号吗?" data-table-id="UserTable" data-action='{:url("remove")}' data-rule="id#{id}" class='layui-btn layui-btn-sm layui-btn-primary'>批量删除</a>
<!--{/if}-->
{/if}
{/block}
{block name="content"}
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
{foreach ['index'=>'系统用户','recycle'=>'回 收 站'] as $k=>$v}{if isset($type) and $type eq $k}
<li data-open="{:url('index')}?type={$k}" class="layui-this">{$v}</li>
{else}
<li data-open="{:url('index')}?type={$k}">{$v}</li>
{/if}{/foreach}
</ul>
<div class="layui-tab-content">
{include file='user/index_search'}
<table id="UserTable" data-url="{:sysuri('index')}" data-target-search="form.form-search"></table>
</div>
</div>
<script>
$(function () {
$('#UserTable').layTable({
even: true, height: 'full',
sort: {field: 'sort desc,id', type: 'desc'},
where: {type: '{$type|default="index"}'},
cols: [[
{checkbox: true, fixed: true},
{field: 'sort', title: '排序权重', width: 100, align: 'center', sort: true, templet: '#SortInputTpl'},
{
field: 'headimg', title: '头像', width: 60, align: 'center', templet: function (d) {
if (!d.headimg) return '-';
return layui.laytpl('<div class="headimg headimg-ss shadow-inset margin-0" data-tips-image data-tips-hover data-lazy-src="{{d.headimg}}"></div>').render(d);
}
},
{field: 'username', title: '登录账号', minWidth: 100, align: 'center', templet: '<div>{{d.username||"-"}}</div>'},
{field: 'nickname', title: '用户名称', minWidth: 100, align: 'center', templet: '<div>{{d.nickname||"-"}}</div>'},
/* {notempty name='bases'} */
{
field: 'usertype', title: '角色身份', minWidth: 100, align: 'center', templet: function (d) {
d.userinfo = d.userinfo || {};
return d.userinfo.code ? (d.userinfo.name + ' ( ' + d.userinfo.code + ' ) ') : '-';
}
},
/* {/notempty} */
// {field: 'contact_mail', title: '联系邮箱', minWidth: 80, templet: '<div>{{d.contact_mail||"-"}}</div>'},
// {field: 'contact_phone', title: '联系电话', minWidth: 80, templet: '<div>{{d.contact_phone||"-"}}</div>'},
{field: 'status', title: '账号状态', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl'},
{field: 'login_num', title: '登录次数', align: 'center', minWidth: 100, sort: true},
{field: 'login_at', title: '最后登录', align: 'center', minWidth: 170, sort: true},
{field: 'create_at', title: '创建时间', align: 'center', minWidth: 170, sort: true},
{toolbar: '#toolbar', title: '操作面板', align: 'center', minWidth: 150, fixed: 'right'}
]]
});
// 数据状态切换操作
layui.form.on('switch(StatusSwitch)', function (obj) {
var data = {id: obj.value, status: obj.elem.checked > 0 ? 1 : 0};
$.form.load("{:url('state')}", data, 'post', function (ret) {
if (ret.code < 1) $.msg.error(ret.info, 3, function () {
$('#UserTable').trigger('reload');
}); else {
$('#UserTable').trigger('reload')
}
return false;
}, false);
});
});
</script>
<!-- 数据状态切换模板 -->
<script type="text/html" id="StatusSwitchTpl">
<!--{if auth("state")}-->
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="已激活|已禁用" lay-filter="StatusSwitch" {{-d.status>0?'checked':''}}>
<!--{else}-->
{{-d.status ? '<b class="color-green">已启用</b>' : '<b class="color-red">已禁用</b>'}}
<!--{/if}-->
</script>
<!-- 列表排序权重模板 -->
<script type="text/html" id="SortInputTpl">
<input type="number" min="0" data-blur-number="0" data-action-blur="{:sysuri()}" data-value="id#{{d.id}};action#sort;sort#{value}" data-loading="false" value="{{d.sort}}" class="layui-input text-center">
</script>
<script type="text/html" id="toolbar">
{if isset($type) and $type eq 'index'}
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-sm" data-event-dbclick data-title="编辑用户" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("pass")}-->
<a class="layui-btn layui-btn-sm layui-btn-normal" data-title="设置密码" data-modal='{:url("pass")}?id={{d.id}}'>密 码</a>
<!--{/if}-->
{else}
<!--{if auth("edit")}-->
<a class="layui-btn layui-btn-sm" data-event-dbclick data-title="编辑用户" data-modal='{:url("edit")}?id={{d.id}}'>编 辑</a>
<!--{/if}-->
<!--{if auth("remove")}-->
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要永久删除此账号吗?" data-action="{:url('remove')}" data-value="id#{{d.id}}">删 除</a>
<!--{/if}-->
{/if}
</script>
{/block}

View File

@ -1,58 +0,0 @@
<form class="layui-form layui-form-pane form-search" action="{:sysuri()}" onsubmit="return false" method="get" autocomplete="off">
<div class="layui-form-item layui-inline">
<label class="layui-form-label">账号名称</label>
<label class="layui-input-inline">
<input name="username" value="{$get.username|default=''}" placeholder="请输入账号或名称" class="layui-input">
</label>
</div>
<!--{notempty name='bases'}-->
<div class="layui-form-item layui-inline">
<label class="layui-form-label">角色身份</label>
<div class="layui-input-inline">
<select name="usertype" lay-search class="layui-select">
<option value=''>-- 全部 --</option>
{foreach $bases as $base}{if $base.code eq input('get.usertype')}
<option selected value="{$base.code|default=''}">{$base.name|default=''} ( {$base.code|default=''} )</option>
{else}
<option value="{$base.code|default=''}">{$base.name|default=''} ( {$base.code|default=''} )</option>
{/if}{/foreach}
</select>
</div>
</div>
<!--{/notempty}-->
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">联系手机</label>
<label class="layui-input-inline">
<input name="phone" value="{$get.phone|default=''}" placeholder="请输入联系手机" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline layui-hide">
<label class="layui-form-label">联系邮箱</label>
<label class="layui-input-inline">
<input name="mail" value="{$get.mail|default=''}" placeholder="请输入联系邮箱" class="layui-input">
</label>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">最后登录</label>
<div class="layui-input-inline">
<input data-date-range name="login_at" value="{$get.login_at|default=''}" placeholder="请选择登录时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">创建时间</label>
<div class="layui-input-inline">
<input data-date-range name="create_at" value="{$get.create_at|default=''}" placeholder="请选择创建时间" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-inline">
<input type="hidden" name="type" value="{$type|default='index'}">
<button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
</div>
</form>

View File

@ -1,50 +0,0 @@
<form action="{:sysuri()}" method="post" data-auto="true" class="layui-form layui-card" data-table-id="UserTable">
<div class="layui-card-body padding-left-40">
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>登录用户账号</b>Username</span>
<!--{if isset($vo) and isset($vo.username)}-->
<input disabled value='{$vo.username|default=""}' class="layui-input think-bg-gray">
<!--{else}-->
<input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入4位及以上字符登录用户账号" class="layui-input">
<!--{/if}-->
</label>
<p class="help-block">登录用户账号创建后,不允许再次修改。</p>
</div>
<!--{if $verify}-->
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>旧的登录密码</b>Old Password</span>
<input type="password" autofocus name="oldpassword" value='' pattern="^\S{1,}$" required placeholder="请输入旧的登录密码" class="layui-input">
</label>
<p class="color-desc">请输入旧密码来验证修改权限,旧密码不限制格式。</p>
</div>
<!--{/if}-->
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>新的登录密码</b>New Password</span>
<input type="password" name="password" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请输入新的登录密码" class="layui-input">
</label>
<p class="color-desc">密码必须包含大小写字母、数字、符号的任意两者组合。</p>
</div>
<div class="layui-form-item">
<label class="relative block">
<span class="help-label"><b>重复登录密码</b>Repeat Password</span>
<input type="password" name="repassword" maxlength="32" pattern="^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$" required placeholder="请重复输入登录密码" class="layui-input">
</label>
<p class="color-desc">密码必须包含大小写字母、数字、符号的任意两者组合。</p>
</div>
</div>
<div class="hr-line-dashed"></div>
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<div class="layui-form-item text-center">
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>

View File

@ -1,81 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderItem;
use app\data\service\OrderService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
use think\Model;
/**
* 商城订单自动清理
* Class OrderClean
* @package app\data\command
*/
class OrderClean extends Command
{
protected function configure()
{
$this->setName('xdata:OrderClean');
$this->setDescription('批量清理商城订单数据');
}
/**
* 业务指令执行
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
$this->_autoCancelOrder();
$this->_autoRemoveOrder();
}
/**
* 自动取消30分钟未支付的订单
* @throws Exception
*/
private function _autoCancelOrder()
{
try {
$map = [['status', '<', 3], ['payment_status', '=', 0]];
$map[] = ['create_at', '<', date('Y-m-d H:i:s', strtotime('-30 minutes'))];
[$count, $total] = [0, ($result = ShopOrder::mk()->where($map)->select())->count()];
$result->map(function (Model $item) use ($total, &$count) {
$this->queue->message($total, ++$count, "开始取消未支付的订单 {$item['order_no']}");
$item->save(['status' => 0, 'cancel_status' => 1, 'cancel_datetime' => date('Y-m-d H:i:s'), 'cancel_remark' => '自动取消30分钟未完成支付']);
OrderService::stock($item['order_no']);
$this->queue->message($total, $count, "完成取消未支付的订单 {$item['order_no']}", 1);
});
} catch (\Exception $exception) {
$this->queue->error($exception->getMessage());
}
}
/**
* 自动清理已经取消的订单
* @throws Exception
*/
private function _autoRemoveOrder()
{
try {
$map = [['status', '=', 0], ['payment_status', '=', 0]];
$map[] = ['create_at', '<', date('Y-m-d H:i:s', strtotime('-3 days'))];
[$count, $total] = [0, ($result = ShopOrder::mk()->where($map)->select())->count()];
$result->map(function (Model $item) use ($total, &$count) {
$this->queue->message($total, ++$count, "开始清理已取消的订单 {$item['order_no']}");
ShopOrder::mk()->where(['order_no' => $item['order_no']])->delete();
ShopOrderItem::mk()->where(['order_no' => $item['order_no']])->delete();
$this->queue->message($total, $count, "完成清理已取消的订单 {$item['order_no']}", 1);
});
} catch (\Exception $exception) {
$this->queue->error($exception->getMessage());
}
}
}

View File

@ -1,79 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserUpgradeService;
use think\admin\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
/**
* 更新用户代理关系
* Class UserAgent
* @package app\data\command
*/
class UserAgent extends Command
{
protected function configure()
{
$this->setName('xdata:UserAgent');
$this->addArgument('uuid', Argument::OPTIONAL, '目标用户', '');
$this->addArgument('puid', Argument::OPTIONAL, '上级代理', '');
$this->setDescription('重新设置用户上级代理, 参数UUID PUID');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function execute(Input $input, Output $output)
{
[$uuid, $puid] = [$input->getArgument('uuid'), $input->getArgument('puid')];
if (empty($uuid)) $this->setQueueError("参数UID无效请传入正确的参数!");
if (empty($puid)) $this->setQueueError("参数PID无效请传入正确的参数!");
// 检查当前用户资料
$user = DataUser::mk()->where(['id' => $uuid])->find();
if (empty($user)) $this->setQueueError("读取用户数据失败!");
// 检查上级代理用户
$parant = DataUser::mk()->where(['id' => $puid])->find();
if (empty($parant)) $this->setQueueError('读取代理数据失败!');
// 检查异常关系处理
if (stripos($parant['path'], "-{$user['id']}-")) {
$this->setQueueError('不能把下级设置为代理!');
}
// 更新自己的代理关系
$path1 = rtrim($parant['path'] ?: '-', '-') . "-{$parant['id']}-";
DataUser::mk()->where(['id' => $user['id']])->update([
'path' => $path1, 'layer' => substr_count($path1, '-'),
'pid0' => $parant['id'], 'pid1' => $parant['id'], 'pid2' => $parant['pid1'],
]);
UserUpgradeService::upgrade($user['id'], true);
$this->setQueueMessage(1, 1, "更新指定用户[{$user['id']}]代理绑定成功!");
// 更新下级的代理关系
$path2 = "{$user['path']}{$user['id']}-";
[$total, $count] = [DataUser::mk()->whereLike('path', "{$path2}%")->count(), 0];
foreach (DataUser::mk()->whereLike('path', "{$path2}%")->order('layer desc')->select() as $vo) {
$this->setQueueMessage($total, ++$count, "开始更新下级用户[{$vo['id']}]代理绑定!");
// 更新下级用户代理数据
$path3 = preg_replace("#^{$path2}#", "{$path1}{$user['id']}-", $vo['path']);
$attrs = array_reverse(str2arr($path3, '-'));
DataUser::mk()->where(['id' => $vo['id']])->update([
'path' => $path3, 'layer' => substr_count($path3, '-'),
'pid0' => $attrs[0] ?? 0, 'pid1' => $attrs[0] ?? 0, 'pid2' => $attrs[1] ?? 0,
]);
$this->setQueueMessage($total, $count, "完成更新下级用户[{$vo['id']}]代理绑定!", 1);
}
}
}

View File

@ -1,45 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserBalanceService;
use app\data\service\UserRebateService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
/**
* 用户余额及返利重算处理
* Class UserBalance
* @package app\data\command
*/
class UserAmount extends Command
{
protected function configure()
{
$this->setName('xdata:UserAmount');
$this->setDescription('批量重新计算余额返利');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
[$total, $count, $error] = [DataUser::mk()->count(), 0, 0];
foreach (DataUser::mk()->field('id')->cursor() as $user) try {
$this->queue->message($total, ++$count, "刷新用户 [{$user['id']}] 余额及返利开始");
UserRebateService::amount($user['id']) && UserBalanceService::amount($user['id']);
$this->queue->message($total, $count, "刷新用户 [{$user['id']}] 余额及返利完成", 1);
} catch (\Exception $exception) {
$error++;
$this->queue->message($total, $count, "刷新用户 [{$user['id']}] 余额及返利失败, {$exception->getMessage()}", 1);
}
$this->setQueueSuccess("此次共处理 {$total} 个刷新操作, 其中有 {$error} 个刷新失败。");
}
}

View File

@ -1,262 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\model\DataUserTransfer;
use app\data\service\UserRebateService;
use think\admin\Command;
use think\admin\Exception;
use think\admin\storage\LocalStorage;
use think\console\Input;
use think\console\Output;
use WePay\Transfers;
use WePay\TransfersBank;
/**
* 用户提现处理
* Class UserTransfer
* @package app\data\command
*/
class UserTransfer extends Command
{
protected function configure()
{
$this->setName('xdata:UserTransfer');
$this->setDescription('批量执行线上打款操作');
}
/**
* 执行微信提现操作
* @param Input $input
* @param Output $output
* @return void
* @throws \think\admin\Exception
*/
protected function execute(Input $input, Output $output)
{
$map = [['type', 'in', ['wechat_banks', 'wechat_wallet']], ['status', 'in', [3, 4]]];
[$total, $count, $error] = [DataUserTransfer::mk()->where($map)->count(), 0, 0];
foreach (DataUserTransfer::mk()->where($map)->cursor() as $vo) try {
$this->queue->message($total, ++$count, "开始处理订单 {$vo['code']} 提现");
if ($vo['status'] === 3) {
$this->queue->message($total, $count, "尝试处理订单 {$vo['code']} 打款", 1);
if ($vo['type'] === 'wechat_banks') {
[$config, $result] = $this->createTransferBank($vo);
} else {
[$config, $result] = $this->createTransferWallet($vo);
}
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'status' => 4,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_no' => $result['partner_trade_no'],
'trade_time' => $result['payment_time'] ?? date('Y-m-d H:i:s'),
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '创建微信提现成功',
]);
} else {
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'change_time' => date('Y-m-d H:i:s'), 'change_desc' => $result['err_code_des'] ?? '线上提现失败',
]);
}
} elseif ($vo['status'] === 4) {
$this->queue->message($total, $count, "刷新提现订单 {$vo['code']} 状态", 1);
if ($vo['type'] === 'wechat_banks') {
$this->queryTransferBank($vo);
} else {
$this->queryTransferWallet($vo);
}
}
} catch (\Exception $exception) {
$error++;
$this->queue->message($total, $count, "处理提现订单 {$vo['code']} 失败, {$exception->getMessage()}", 1);
DataUserTransfer::mk()->where(['code' => $vo['code']])->update([
'change_time' => date('Y-m-d H:i:s'), 'change_desc' => $exception->getMessage(),
]);
}
$this->setQueueSuccess("此次共处理 {$total} 笔提现操作, 其中有 {$error} 笔处理失败。");
}
/**
* 尝试提现转账到银行卡
* @param array $item
* @return array [config, result]
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createTransferBank(array $item): array
{
$config = $this->getConfig($item['uuid']);
return [$config, TransfersBank::instance($config)->create([
'partner_trade_no' => $item['code'],
'enc_bank_no' => $item['bank_code'],
'enc_true_name' => $item['bank_user'],
'bank_code' => $item['bank_wseq'],
'amount' => intval($item['amount'] - $item['charge_amount']) * 100,
'desc' => '微信银行卡提现',
])];
}
/**
* 获取微信提现参数
* @param int $uuid
* @return array
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getConfig(int $uuid): array
{
$data = sysdata('TransferWxpay');
if (empty($data)) throw new Exception('未配置微信提现商户');
// 商户证书文件处理
$local = LocalStorage::instance();
if (!$local->has($file1 = "{$data['wechat_mch_id']}_key.pem", true)) {
$local->set($file1, $data['wechat_mch_key_text'], true);
}
if (!$local->has($file2 = "{$data['wechat_mch_id']}_cert.pem", true)) {
$local->set($file2, $data['wechat_mch_cert_text'], true);
}
// 获取用户支付信息
$result = $this->getWechatInfo($uuid, $data['wechat_type']);
if (empty($result)) throw new Exception('无法读取打款数据');
return [
'appid' => $result[0],
'openid' => $result[1],
'mch_id' => $data['wechat_mch_id'],
'mch_key' => $data['wechat_mch_key'],
'ssl_key' => $local->path($file1, true),
'ssl_cer' => $local->path($file2, true),
'cache_path' => $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'wechat',
];
}
/**
* 根据配置获取用户OPENID
* @param int $uuid
* @param string $type
* @return mixed|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getWechatInfo(int $uuid, string $type): ?array
{
$user = DataUser::mk()->where(['id' => $uuid])->find();
if (empty($user)) return null;
$appid1 = sysconf('data.wxapp_appid');
if (strtolower(sysconf('wechat.type')) === 'api') {
$appid2 = sysconf('wechat.appid');
} else {
$appid2 = sysconf('wechat.thr_appid');
}
if ($type === 'normal') {
if (!empty($user['openid1'])) return [$appid1, $user['openid1']];
if (!empty($user['openid2'])) return [$appid2, $user['openid2']];
}
if ($type === 'wxapp' && !empty($user['openid1'])) {
return [$appid1, $user['openid1']];
}
if ($type === 'wechat' && !empty($user['openid2'])) {
return [$appid2, $user['openid2']];
}
return null;
}
/**
* 尝试提现转账到微信钱包
* @param array $item
* @return array [config, result]
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createTransferWallet(array $item): array
{
$config = $this->getConfig($item['uuid']);
return [$config, Transfers::instance($config)->create([
'openid' => $config['openid'],
'amount' => intval($item['amount'] - $item['charge_amount']) * 100,
'partner_trade_no' => $item['code'],
'spbill_create_ip' => '127.0.0.1',
'check_name' => 'NO_CHECK',
'desc' => '微信余额提现',
])];
}
/**
* 查询更新提现打款状态
* @param array $item
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function queryTransferBank(array $item)
{
$config = $this->getConfig($item['uuid']);
[$config['appid'], $config['openid']] = [$item['appid'], $item['openid']];
$result = TransfersBank::instance($config)->query($item['trade_no']);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
if ($result['status'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 5,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_time' => $result['pay_succ_time'] ?: date('Y-m-d H:i:s'),
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款成功',
]);
}
if (in_array($result['status'], ['FAILED', 'BANK_FAIL'])) {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 0,
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款失败',
]);
// 刷新用户可提现余额
UserRebateService::amount($item['uuid']);
}
}
}
/**
* 查询更新提现打款状态
* @param array $item
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function queryTransferWallet(array $item)
{
$config = $this->getConfig($item['uuid']);
[$config['appid'], $config['openid']] = [$item['appid'], $item['openid']];
$result = Transfers::instance($config)->query($item['trade_no']);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
DataUserTransfer::mk()->where(['code' => $item['code']])->update([
'status' => 5,
'appid' => $config['appid'],
'openid' => $config['openid'],
'trade_time' => $result['payment_time'],
'change_time' => date('Y-m-d H:i:s'),
'change_desc' => '微信提现打款成功',
]);
}
}
}

View File

@ -1,47 +0,0 @@
<?php
namespace app\data\command;
use app\data\model\DataUser;
use app\data\service\UserUpgradeService;
use think\admin\Command;
use think\admin\Exception;
use think\console\Input;
use think\console\Output;
/**
* 用户等级重算处理
* Class UserLevel
* @package app\data\command
*/
class UserUpgrade extends Command
{
protected function configure()
{
$this->setName('xdata:UserUpgrade');
$this->setDescription('批量重新计算用户等级');
}
/**
* @param Input $input
* @param Output $output
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
try {
[$total, $count] = [DataUser::mk()->count(), 0];
foreach (DataUser::mk()->field('id')->cursor() as $user) {
$this->queue->message($total, ++$count, "正在计算用户 [{$user['id']}] 的等级");
UserUpgradeService::upgrade($user['id']);
$this->queue->message($total, $count, "完成计算用户 [{$user['id']}] 的等级", 1);
}
$this->setQueueSuccess("此次共重新计算 {$total} 个用户等级。");
} catch (Exception $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->setQueueError($exception->getMessage());
}
}
}

View File

@ -1,95 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use app\data\service\UserTokenService;
use think\admin\Controller;
use think\exception\HttpResponseException;
/**
* 接口授权认证基类
* Class Auth
* @package app\data\controller\api
*/
abstract class Auth extends Controller
{
/**
* 当前接口请求终端类型
* >>>>>>>>>>>>>>>>>>>>>>
* >>> api-name 接口类型
* >>> api-token 接口认证
* >>>>>>>>>>>>>>>>>>>>>>
* --- 手机浏览器访问 wap
* --- 电脑浏览器访问 web
* --- 微信小程序访问 wxapp
* --- 微信服务号访问 wechat
* --- 苹果应用接口访问 isoapp
* --- 安卓应用接口访问 android
* @var string
*/
protected $type;
/**
* 当前用户编号
* @var integer
*/
protected $uuid;
/**
* 当前用户数据
* @var array
*/
protected $user;
/**
* 控制器初始化
*/
protected function initialize()
{
// 检查接口类型
$this->type = $this->request->header('api-name');
if (empty($this->type)) $this->error("接口类型异常!");
if (!isset(UserAdminService::TYPES[$this->type])) {
$this->error("接口类型[{$this->type}]未定义!");
}
// 读取用户数据
$this->user = $this->getUser();
$this->uuid = $this->user['id'] ?? '';
if (empty($this->uuid)) {
$this->error('用户登录失败!', '{-null-}', 401);
}
}
/**
* 获取用户数据
* @return array
*/
protected function getUser(): array
{
try {
if (empty($this->uuid)) {
$token = $this->request->header('api-token');
if (empty($token)) $this->error('登录认证不能为空!');
[$state, $info, $this->uuid] = UserTokenService::check($this->type, $token);
if (empty($state)) $this->error($info, '{-null-}', 401);
}
return UserAdminService::get($this->uuid, $this->type);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
/**
* 显示用户禁用提示
*/
protected function checkUserStatus()
{
if (empty($this->user['status'])) {
$this->error('账户已被冻结!');
}
}
}

View File

@ -1,64 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\BaseUserMessage;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\admin\model\SystemBase;
/**
* 基础数据接口
* Class Data
* @package app\data\controller\api
*/
class Data extends Controller
{
/**
* 获取指定数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getData()
{
$data = $this->_vali(['name.require' => '数据名称不能为空!']);
$extra = ['about', 'slider', 'agreement', 'cropper']; // 其他数据
if (in_array($data['name'], $extra) || isset(SystemBase::items('页面内容')[$data['name']])) {
$this->success('获取数据对象', sysdata($data['name']));
} else {
$this->error('获取数据失败', []);
}
}
/**
* 图片内容数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getSlider()
{
$this->keys = input('keys', '首页图片');
if (isset(SystemBase::items('图片内容')[$this->keys])) {
$this->success('获取图片内容', sysdata($this->keys));
} else {
$this->error('获取图片失败', []);
}
}
/**
* 系统通知数据
*/
public function getNotify()
{
BaseUserMessage::mQuery(null, function (QueryHelper $query) {
if (($id = input('id')) > 0) {
BaseUserMessage::mk()->where(['id' => $id])->inc('num_read')->update([]);
}
$query->equal('id')->where(['status' => 1, 'deleted' => 0]);
$this->success('获取系统通知', $query->order('sort desc,id desc')->page(true, false, false, 20));
});
}
}

View File

@ -1,63 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\ShopGoods;
use app\data\model\ShopGoodsCate;
use app\data\model\ShopGoodsMark;
use app\data\service\ExpressService;
use app\data\service\GoodsService;
use think\admin\Controller;
/**
* 商品数据接口
* Class Goods
* @package app\data\controller\api
*/
class Goods extends Controller
{
/**
* 获取分类数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCate()
{
$this->success('获取分类成功', ShopGoodsCate::treeData());
}
/**
* 获取标签数据
*/
public function getMark()
{
$this->success('获取标签成功', ShopGoodsMark::items());
}
/**
* 获取商品数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getGoods()
{
// 更新访问统计
$map = $this->_vali(['code.default' => '']);
if ($map['code']) ShopGoods::mk()->where($map)->inc('num_read')->update([]);
// 商品数据处理
$query = ShopGoods::mQuery()->like('name,marks,cateids,payment')->equal('code,vip_entry');
$result = $query->where(['deleted' => 0, 'status' => 1])->order('sort desc,id desc')->page(true, false, false, 10);
if (count($result['list']) > 0) GoodsService::bindData($result['list']);
$this->success('获取商品数据', $result);
}
/**
* 获取配送区域
*/
public function getRegion()
{
$this->success('获取区域成功', ExpressService::region(3, 1));
}
}

View File

@ -1,109 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\DataUser;
use app\data\service\MessageService;
use app\data\service\UserAdminService;
use think\admin\Controller;
/**
* 用户登录注册接口
* Class Login
* @package app\data\controller\api
*/
class Login extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type;
/**
* 控制器初始化
*/
protected function initialize()
{
// 接收接口类型
$this->type = $this->request->request('api');
$this->type = $this->type ?: $this->request->header('api-name');
$this->type = $this->type ?: $this->request->header('api-type');
$this->type = $this->type ?: UserAdminService::API_TYPE_WAP;
if (empty(UserAdminService::TYPES[$this->type])) {
$this->error("接口支付[{$this->type}]未定义规则!");
}
}
/**
* 用户登录接口
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function in()
{
$data = $this->_vali([
'phone.mobile' => '手机号码格式错误!',
'phone.require' => '手机号码不能为空!',
'password.require' => '登录密码不能为空!',
]);
$map = ['deleted' => 0, 'phone' => $data['phone']];
$user = DataUser::mk()->where($map)->findOrEmpty();
if ($user->isEmpty()) $this->error('该手机号还没有注册哦!');
if (empty($user['status'])) $this->error('该用户账号状态异常!');
if (md5($data['password']) === $user['password']) {
$this->success('手机登录成功!', UserAdminService::set($map, [], $this->type, true));
} else {
$this->error('账号登录失败,请稍候再试!');
}
}
/**
* 用户统一注册入口
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
*/
public function register()
{
$data = $this->_vali([
'region_province.default' => '',
'region_city.default' => '',
'region_area.default' => '',
'username.default' => '',
'phone.mobile' => '手机格式错误!',
'phone.require' => '手机不能为空!',
'verify.require' => '验证码不能为空!',
'password.require' => '登录密码不能为空!',
]);
if (!MessageService::instance()->checkVerifyCode($data['verify'], $data['phone'])) {
$this->error('手机短信验证失败!');
}
$map = ['phone' => $data['phone'], 'deleted' => 0];
if (DataUser::mk()->where($map)->count() > 0) {
$this->error('手机号已注册,请使用其它手机号!');
}
$data['password'] = md5($data['password']);
$user = UserAdminService::set($map, $data, $this->type, true);
empty($user) ? $this->error('手机注册失败!') : $this->success('用户注册成功!', $user);
}
/**
* 发送短信验证码
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sendsms()
{
$data = $this->_vali([
'phone.mobile' => '手机号格式错误!',
'phone.require' => '手机号不能为空!',
'secure.require' => '安全码不能为空!',
]);
if ($data['secure'] !== sysconf('zt.secure_code')) $this->error('接口安全码错误!');
[$state, $message, $data] = MessageService::instance()->sendVerifyCode($data['phone']);
$state ? $this->success($message, $data) : $this->error($message, $data);
}
}

View File

@ -1,68 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\model\DataNewsItem;
use app\data\model\DataNewsMark;
use app\data\model\DataNewsXCollect;
use app\data\service\NewsService;
use think\admin\Controller;
/**
* 文章接口控制器
* Class News
* @package app\data\controller\api
*/
class News extends Controller
{
/**
* 获取文章标签列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getMark()
{
$query = DataNewsMark::mQuery()->like('name');
$query->where(['status' => 1, 'deleted' => 0])->withoutField('sort,status,deleted');
$this->success('获取文章标签', $query->order('sort desc,id desc')->page(false, false));
}
/**
* 获取文章内容列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getItem()
{
if ($code = input('code', '')) {
DataNewsItem::mk()->where(['code' => $code])->inc('num_read')->update([]);
if (($uuid = input('uuid', 0)) > 0) {
$data = ['uuid' => $uuid, 'code' => $code, 'type' => 3, 'status' => 2];
DataNewsXCollect::mk()->where($data)->delete();
DataNewsXCollect::mk()->insert($data);
}
}
$query = DataNewsItem::mQuery()->like('name,mark')->equal('id,code');
$query->where(['deleted' => 0, 'status' => 1])->withoutField('sort,status,deleted');
$result = $query->order('sort desc,id desc')->page(true, false, false, 15);
NewsService::buildData($result['list'], input('uuid', 0));
$this->success('获取文章内容', $result);
}
/**
* 获取文章评论
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getComment()
{
$map = $this->_vali(['code.require' => '文章不能为空!']);
$query = DataNewsXCollect::mQuery()->where(['type' => 4, 'status' => 2]);
$result = $query->where($map)->order('id desc')->page(true, false, false, 15);
NewsService::buildListByUidAndCode($result['list']);
$this->success('获取评论成功', $result);
}
}

View File

@ -1,64 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\payment\AlipayPaymentService;
use app\data\service\payment\JoinpayPaymentService;
use app\data\service\payment\WechatPaymentService;
use think\admin\Controller;
/**
* 异步通知处理
* Class Notify
* @package app\data\controller\api
*/
class Notify extends Controller
{
/**
* 微信支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \think\admin\Exception
*/
public function wxpay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return WechatPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
/**
* 支付宝支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \think\admin\Exception
*/
public function alipay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return AlipayPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
/**
* 汇聚支付通知
* @param string $scene 支付场景
* @param string $param 支付参数
* @return string
* @throws \think\admin\Exception
*/
public function joinpay(string $scene = 'order', string $param = ''): string
{
if (strtolower($scene) === 'order') {
return JoinpayPaymentService::instance($param)->notify();
} else {
return 'success';
}
}
}

View File

@ -1,137 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use app\wechat\service\WechatService;
use think\admin\Controller;
use think\Response;
/**
* 微信服务号入口
* Class Wechat
* @package app\data\controller\api
* @example 域名请修改为自己的地址,放到网页代码合适位置
* <meta name="referrer" content="always">
* <script referrerpolicy="unsafe-url" src="https://your.domain.com/data/api.wechat/oauth?mode=1"></script>
*
* 授权模式支持两种模块,参数 mode=0 时为静默授权mode=1 时为完整授权
* 注意:回跳地址默认从 Header 中的 http_referer 获取,也可以传 source 参数
*/
class Wechat extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type = UserAdminService::API_TYPE_WECHAT;
/**
* 唯一绑定字段
* @var string
*/
private $field;
/**
* 控制器初始化
* @return $this
*/
protected function initialize(): Wechat
{
if (empty(UserAdminService::TYPES[$this->type]['auth'])) {
$this->error("接口类型[{$this->type}]没有定义规则");
} else {
$this->field = UserAdminService::TYPES[$this->type]['auth'];
}
return $this;
}
/**
* 获取 JSSDK 签名
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function jssdk()
{
$url = input('source') ?: $this->request->server('http_referer');
$this->success('获取签名参数', WechatService::instance()->getWebJssdkSign($url));
}
/**
* 加载网页授权数据
* @return Response
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function oauth(): Response
{
$source = input('source') ?: $this->request->server('http_referer');
[$mode, $script, $wechat] = [input('mode', 1), [], WechatService::instance()];
$result = $wechat->getWebOauthInfo($source ?: $this->request->url(true), $mode, false);
if (empty($result['openid'])) {
$script[] = 'alert("Wechat WebOauth failed.")';
} else {
$data = $result['fansinfo'] ?? [];
$data[$this->field] = $data['openid'];
$data['base_sex'] = ['未知', '男', '女'][$data['sex']] ?? '未知';
if (isset($result['unionid'])) $data['unionid'] = $result['unionid'];
if (isset($data['headimgurl'])) $data['headimg'] = $data['headimgurl'];
$map = UserAdminService::getUserUniMap($this->field, $data[$this->field], $data['unionid'] ?? '');
$result['userinfo'] = UserAdminService::set($map, array_merge($map, $data), $this->type, true);
$script[] = "window.WeChatOpenid='{$result['openid']}'";
$script[] = 'window.WeChatFansInfo=' . json_encode($result['fansinfo'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
$script[] = 'window.WeChatUserInfo=' . json_encode($result['userinfo'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
$script[] = '';
return Response::create(join(";\n", $script))->contentType('application/x-javascript');
}
/**
* 网页授权测试
* 使用网页直接访问此链接
* @return string
*/
public function otest(): string
{
return <<<EOL
<html lang="zh">
<head>
<meta charset="utf-8">
<title>微信网页授权测试</title>
<meta name="referrer" content="always">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<style>pre{padding:20px;overflow:auto;margin-top:10px;background:#ccc;border-radius:6px;}</style>
</head>
<body>
<div>当前链接</div>
<pre>{$this->request->scheme()}://{$this->request->host()}/data/api.wechat/oauth?mode=1</pre>
<div style="margin-top:30px">粉丝数据</div>
<pre id="fansdata">待网页授权,加载粉丝数据...</pre>
<div style="margin-top:30px">用户数据</div>
<pre id="userdata">待网页授权,加载用户数据...</pre>
<script referrerpolicy="unsafe-url" src="//{$this->request->host()}/data/api.wechat/oauth?mode=1"></script>
<script>
if(typeof window.WeChatFansInfo === 'object'){
document.getElementById('fansdata').innerText = JSON.stringify(window.WeChatFansInfo, null, 2);
}
if(typeof window.WeChatUserInfo === 'object'){
document.getElementById('userdata').innerText = JSON.stringify(window.WeChatUserInfo, null, 2);
}
</script>
</body>
</html>
EOL;
}
}

View File

@ -1,200 +0,0 @@
<?php
namespace app\data\controller\api;
use app\data\service\UserAdminService;
use think\admin\Controller;
use think\exception\HttpResponseException;
use think\Response;
use WeMini\Crypt;
use WeMini\Live;
use WeMini\Qrcode;
/**
* 微信小程序入口
* Class Wxapp
* @package app\data\controller\api
*/
class Wxapp extends Controller
{
/**
* 接口认证类型
* @var string
*/
private $type = UserAdminService::API_TYPE_WXAPP;
/**
* 唯一绑定字段
* @var string
*/
private $field;
/**
* 小程序配置参数
* @var array
*/
private $cfg;
/**
* 接口服务初始化
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function initialize()
{
$opt = sysdata('wxapp');
$this->cfg = [
'appid' => $opt['appid'] ?? '',
'appsecret' => $opt['appkey'] ?? '',
'cache_path' => $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'wechat',
];
if (empty(UserAdminService::TYPES[$this->type]['auth'])) {
$this->error("接口类型[{$this->type}]没有定义规则");
} else {
$this->field = UserAdminService::TYPES[$this->type]['auth'];
}
}
/**
* 授权Code换取会话信息
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
*/
public function session()
{
$input = $this->_vali(['code.require' => '登录凭证CODE不能为空']);
[$openid, $unionid, $session] = $this->applySessionKey($input['code']);
$map = UserAdminService::getUserUniMap($this->field, $openid, $unionid);
$data = [$this->field => $openid, 'session_key' => $session];
if (!empty($unionid)) $data['unionid'] = $unionid;
$this->success('授权换取成功!', UserAdminService::set($map, $data, $this->type, true));
}
/**
* 小程序数据解密
*/
public function decode()
{
try {
$input = $this->_vali([
'iv.require' => '解密向量不能为空!',
'code.require' => '授权CODE不能为空',
'encrypted.require' => '加密内容不能为空!',
]);
[$openid, $unionid, $input['session_key']] = $this->applySessionKey($input['code']);
$result = Crypt::instance($this->cfg)->decode($input['iv'], $input['session_key'], $input['encrypted']);
if (is_array($result) && isset($result['avatarUrl']) && isset($result['nickName'])) {
$data = [$this->field => $openid, 'nickname' => $result['nickName'], 'headimg' => $result['avatarUrl']];
$data['base_sex'] = ['-', '男', '女'][$result['gender']] ?? '-';
if (!empty($unionid)) $data['unionid'] = $unionid;
$map = UserAdminService::getUserUniMap($this->field, $openid, $unionid);
$this->success('数据解密成功!', UserAdminService::set($map, $data, $this->type, true));
} elseif (is_array($result)) {
$this->success('数据解密成功!', $result);
} else {
$this->error('数据处理失败,请稍候再试!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error("数据处理失败,{$exception->getMessage()}");
}
}
/**
* 授权CODE换取会话信息
* @param string $code 换取授权CODE
* @return array [openid, sessionkey]
*/
private function applySessionKey(string $code): array
{
try {
$cache = $this->app->cache->get($code, []);
if (isset($cache['openid']) && isset($cache['session_key'])) {
return [$cache['openid'], $cache['unionid'] ?? '', $cache['session_key']];
}
$result = Crypt::instance($this->cfg)->session($code);
if (isset($result['openid']) && isset($result['session_key'])) {
$this->app->cache->set($code, $result, 60);
return [$result['openid'], $result['unionid'] ?? '', $result['session_key']];
} elseif (isset($result['errmsg'])) {
$this->error($result['errmsg']);
} else {
$this->error("授权换取失败,请稍候再试!");
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error("授权换取失败,{$exception->getMessage()}");
}
}
/**
* 获取小程序码
*/
public function qrcode(): Response
{
try {
$data = $this->_vali([
'size.default' => 430,
'type.default' => 'base64',
'path.require' => '跳转路径不能为空!',
]);
$result = Qrcode::instance($this->cfg)->createMiniPath($data['path'], $data['size']);
if ($data['type'] === 'base64') {
$this->success('生成小程序码成功!', [
'base64' => 'data:image/png;base64,' . base64_encode($result),
]);
} else {
return response($result)->contentType('image/png');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
/**
* 获取直播列表
*/
public function getLiveList()
{
try {
$data = $this->_vali(['start.default' => 0, 'limit.default' => 10]);
$list = Live::instance($this->cfg)->getLiveList($data['start'], $data['limit']);
$this->success('获取直播列表成功!', $list);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
/**
* 获取回放源视频
*/
public function getLiveInfo()
{
try {
$data = $this->_vali([
'start.default' => 0,
'limit.default' => 10,
'action.default' => 'get_replay',
'room_id.require' => '直播间不能为空',
]);
$result = Live::instance($this->cfg)->getLiveInfo($data);
$this->success('获取回放视频成功!', $result);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
}

View File

@ -1,132 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserAddress;
use think\admin\extend\CodeExtend;
/**
* 用户收货地址管理
* Class Address
* @package app\data\controller\api\auth
*/
class Address extends Auth
{
/**
* 添加收货地址
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function set()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.default' => 0,
'code.default' => '',
'idcode.default' => '', // 身份证号码
'idimg1.default' => '', // 身份证正面
'idimg2.default' => '', // 身份证反面
'type.in:0,1' => '地址状态不在范围!',
'name.require' => '收货姓名不能为空!',
'phone.mobile' => '收货手机格式错误!',
'phone.require' => '收货手机不能为空!',
'province.require' => '地址省份不能为空!',
'city.require' => '地址城市不能为空!',
'area.require' => '地址区域不能为空!',
'address.require' => '详情地址不能为空!',
'deleted.value' => 0,
]);
if (empty($data['code'])) {
unset($data['code']);
$count = DataUserAddress::mk()->where($data)->count();
if ($count > 0) $this->error('抱歉,该地址已经存在!');
$data['code'] = CodeExtend::uniqidDate(20, 'A');
if (DataUserAddress::mk()->insert($data) === false) {
$this->error('添加地址失败!');
}
} else {
$map = ['uuid' => $this->uuid, 'code' => $data['code']];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('修改地址不存在!');
DataUserAddress::mk()->where($map)->update($data);
}
// 去除其它默认选项
if (isset($data['type']) && $data['type'] > 0) {
$map = [['uuid', '=', $this->uuid], ['code', '<>', $data['code']]];
DataUserAddress::mk()->where($map)->update(['type' => 0]);
}
$this->success('地址保存成功!', $this->getAddress($data['code']));
}
/**
* 获取收货地址
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$query = DataUserAddress::mQuery()->withoutField('deleted');
$query->equal('code')->where(['uuid' => $this->uuid, 'deleted' => 0]);
$result = $query->order('type desc,id desc')->page(false, false, false, 15);
$this->success('获取地址数据!', $result);
}
/**
* 修改地址状态
*/
public function state()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.in:0,1' => '地址状态不在范围!',
'type.require' => '地址状态不能为空!',
'code.require' => '地址编号不能为空!',
]);
// 检查地址是否存在
$map = ['uuid' => $data['uuid'], 'code' => $data['code']];
if (DataUserAddress::mk()->where($map)->count() < 1) {
$this->error('修改的地址不存在!');
}
// 更新默认地址状态
$data['type'] = intval($data['type']);
DataUserAddress::mk()->where($map)->update(['type' => $data['type']]);
// 去除其它默认选项
if ($data['type'] > 0) {
$map = [['uuid', '=', $this->uuid], ['code', '<>', $data['code']]];
DataUserAddress::mk()->where($map)->update(['type' => 0]);
}
$this->success('默认设置成功!', $this->getAddress($data['code']));
}
/**
* 删除收货地址
*/
public function remove()
{
$map = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空!',
]);
$item = DataUserAddress::mk()->where($map)->findOrEmpty();
if ($item->isEmpty()) $this->error('需要删除的地址不存在!');
if ($item->save(['deleted' => 1]) !== false) {
$this->success('删除地址成功!');
} else {
$this->error('删除地址失败!');
}
}
/**
* 获取指定的地址
* @param string $code
* @return null|array
*/
private function getAddress(string $code): array
{
$map = ['code' => $code, 'uuid' => $this->uuid, 'deleted' => 0];
return DataUserAddress::mk()->withoutField('deleted')->where($map)->findOrEmpty()->toArray();
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserBalance;
use think\admin\helper\QueryHelper;
/**
* 用户余额转账
* Class Balance
* @package app\data\controller\api\auth
*/
class Balance extends Auth
{
/**
* 获取用户余额记录
*/
public function get()
{
DataUserBalance::mQuery(null, function (QueryHelper $query) {
$query->withoutField('deleted,create_by');
$query->where(['uuid' => $this->uuid, 'deleted' => 0])->like('create_at#date');
$this->success('获取数据成功', $query->order('id desc')->page(true, false, false, 10));
});
}
}

View File

@ -1,150 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\BaseUserUpgrade;
use app\data\model\DataUser;
use app\data\service\UserAdminService;
use app\data\service\UserUpgradeService;
use think\admin\Storage;
use think\exception\HttpResponseException;
/**
* 用户资料管理
* Class Center
* @package app\data\controller\api\auth
*/
class Center extends Auth
{
/**
* 更新用户资料
*/
public function set()
{
$data = $this->_vali([
'headimg.default' => '',
'username.default' => '',
'base_age.default' => '',
'base_sex.default' => '',
'base_height.default' => '',
'base_weight.default' => '',
'base_birthday.default' => '',
]);
foreach ($data as $key => $vo) if ($vo === '') unset($data[$key]);
if (empty($data)) $this->error('没有修改的数据!');
if (DataUser::mk()->where(['id' => $this->uuid])->update($data) !== false) {
$this->success('更新资料成功!', $this->getUser());
} else {
$this->error('更新资料失败!');
}
}
/**
* 获取用户资料
*/
public function get()
{
$this->success('获取用户资料', $this->getUser());
}
/**
* Base64 图片上传
*/
public function image()
{
try {
$data = $this->_vali(['base64.require' => '图片内容不为空!']);
if (preg_match($preg = '|^data:image/(.*?);base64,|i', $data['base64'])) {
[$ext, $img] = explode('|||', preg_replace($preg, '$1|||', $data['base64']));
if (empty($ext) || !in_array(strtolower($ext), ['png', 'jpg', 'jpeg'])) {
$this->error('图片格式异常!');
}
$name = Storage::name($img, $ext, 'image/');
$info = Storage::instance()->set($name, base64_decode($img));
$this->success('图片上传成功!', ['url' => $info['url']]);
} else {
$this->error('解析内容失败!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
/**
* 二进制文件上传
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function upload()
{
$file = $this->request->file('file');
if (empty($file)) $this->error('文件上传异常!');
$extension = strtolower($file->getOriginalExtension());
if (in_array($extension, ['php', 'sh'])) $this->error('禁止上传此类文件!');
$bina = file_get_contents($file->getRealPath());
$name = Storage::name($file->getPathname(), $extension, '', 'md5_file');
$info = Storage::instance()->set($name, $bina, false, $file->getOriginalName());
if (is_array($info) && isset($info['url'])) {
$this->success('文件上传成功!', $info);
} else {
$this->error('文件上传失败!');
}
}
/**
* 获取用户等级
*/
public function levels()
{
$levels = BaseUserUpgrade::items();
$this->success('获取用户等级', array_values($levels));
}
/**
* 获取我邀请的朋友
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getFrom()
{
$map = [];
$map[] = ['deleted', '=', 0];
$map[] = ['path', 'like', "%-{$this->uuid}-%"];
// 查询邀请的朋友
$query = DataUser::mQuery()->like('nickname|username#nickname')->equal('vip_code,pids,pid1,id#uuid');
$query->field('id,pid0,pid1,pid2,pids,username,nickname,headimg,order_amount_total,teams_amount_total,teams_amount_direct,teams_amount_indirect,teams_users_total,teams_users_direct,teams_users_indirect,rebate_total,rebate_used,rebate_lock,create_at');
$result = $query->where($map)->order('id desc')->page(true, false, false, 15);
// 统计当前用户所有下属数
$total = DataUser::mk()->where($map)->count();
// 统计当前用户本月下属数
$map[] = ['create_at', 'like', date('Y-m-%')];
$month = DataUser::mk()->where($map)->count();
// 返回结果列表数据及统计
$result['total'] = ['user_total' => $total, 'user_month' => $month];
$this->success('获取我邀请的朋友', $result);
}
/**
* 绑定用户邀请人
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function bindFrom()
{
$data = $this->_vali(['from.require' => '邀请人不能为空']);
[$state, $message] = UserUpgradeService::bindAgent($this->uuid, $data['from'], 0);
if ($state) {
$this->success($message, UserAdminService::total($this->uuid));
} else {
$this->error($message, UserAdminService::total($this->uuid));
}
}
}

View File

@ -1,209 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataNewsXCollect;
use app\data\service\NewsService;
/**
* 文章评论内容
* Class News
* @package app\data\controller\api\auth
*/
class News extends Auth
{
/**
* 用户评论内容
*/
public function addComment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 4,
'status.value' => 1,
'code.require' => '文章不能为空!',
'reply.require' => '评论不能为空!',
]);
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::syncNewsTotal($data['code']);
$this->success('添加评论成功!');
} else {
$this->error('添加评论失败!');
}
}
/**
* 获取我的评论
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getComment()
{
$query = DataNewsXCollect::mQuery()->where(['uuid' => $this->uuid, 'type' => 4]);
$result = $query->whereIn('status', [1, 2])->order('id desc')->page(true, false);
NewsService::buildListByUidAndCode($result);
$this->success('获取评论列表成功', $result);
}
/**
* 删除内容评论
*/
public function delComment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 4,
'id.require' => '评论编号不能为空!',
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
$this->success('评论删除成功!');
} else {
$this->error('认证删除失败!');
}
}
/**
* 添加内容收藏
*/
public function addCollect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 1,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->count() > 0) {
$this->success('您已收藏!');
}
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::syncNewsTotal($data['code']);
$this->success('收藏成功!');
} else {
$this->error('收藏失败!');
}
}
/**
* 取消收藏文章
*/
public function delCollect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 1,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
NewsService::syncNewsTotal($data['code']);
$this->success('取消收藏成功!');
} else {
$this->error('取消收藏失败!');
}
}
/**
* 获取用户收藏的资讯
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCollect()
{
$map = ['uuid' => $this->uuid, 'type' => 1];
$query = DataNewsXCollect::mQuery()->where($map);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::buildListByUidAndCode($result['list']);
$this->success('获取收藏记录成功!', $result);
}
/**
* 添加内容点赞
*/
public function addLike()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->count() > 0) {
$this->success('您已点赞!');
}
if (DataNewsXCollect::mk()->insert($data) !== false) {
NewsService::syncNewsTotal($data['code']);
$this->success('点赞成功!');
} else {
$this->error('点赞失败!');
}
}
/**
* 取消内容点赞
*/
public function delLike()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'code.require' => '文章编号不能为空!',
]);
if (DataNewsXCollect::mk()->where($data)->delete() !== false) {
NewsService::syncNewsTotal($data['code']);
$this->success('取消点赞成功!');
} else {
$this->error('取消点赞失败!');
}
}
/**
* 获取用户收藏的资讯
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getLike()
{
$query = DataNewsXCollect::mQuery();
$query->where(['uuid' => $this->uuid, 'type' => 2, 'status' => 2]);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::buildListByUidAndCode($result['list']);
$this->success('获取点赞记录成功!', $result);
}
/**
* 添加用户的浏览历史
*/
public function addHistory()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'type.value' => 2,
'status.value' => 2,
'code.require' => '文章编号不能为空!',
]);
DataNewsXCollect::mk()->where($data)->delete();
DataNewsXCollect::mk()->insert($data);
$this->success('添加浏览历史成功!');
}
/**
* 获取用户的浏览历史
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getHistory()
{
$query = DataNewsXCollect::mQuery();
$query->where(['uuid' => $this->uuid, 'type' => 3, 'status' => 2]);
$result = $query->order('id desc')->page(true, false, false, 15);
NewsService::buildListByUidAndCode($result['list']);
$this->success('获取浏览历史成功!', $result);
}
}

View File

@ -1,496 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\BaseUserPayment;
use app\data\model\DataUser;
use app\data\model\DataUserAddress;
use app\data\model\ShopGoods;
use app\data\model\ShopGoodsItem;
use app\data\model\ShopOrder;
use app\data\model\ShopOrderItem;
use app\data\model\ShopOrderSend;
use app\data\service\ExpressService;
use app\data\service\GoodsService;
use app\data\service\OrderService;
use app\data\service\PaymentService;
use app\data\service\UserAdminService;
use think\admin\extend\CodeExtend;
use think\exception\HttpResponseException;
/**
* 用户订单数据接口
* Class Order
* @package app\data\controller\api\auth
*/
class Order extends Auth
{
/**
* 控制器初始化
*/
protected function initialize()
{
parent::initialize();
if (empty($this->user['status'])) {
$this->error('账户已被冻结,不能操作订单数据哦!');
}
}
/**
* 获取订单列表
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$map = ['uuid' => $this->uuid, 'deleted_status' => 0];
$query = ShopOrder::mQuery()->in('status')->equal('order_no');
$result = $query->where($map)->order('id desc')->page(true, false, false, 20);
if (count($result['list']) > 0) OrderService::buildData($result['list']);
$this->success('获取订单数据成功!', $result);
}
/**
* 用户创建订单
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
// 检查用户状态
$this->checkUserStatus();
// 商品规则
$rules = $this->request->post('items', '');
if (empty($rules)) $this->error('商品不能为空');
// 订单数据
[$items, $order, $truckType, $allowPayments] = [[], [], -1, null];
$order['uuid'] = $this->uuid;
$order['order_no'] = CodeExtend::uniqidDate(18, 'N');
// 代理处理
$order['puid1'] = input('from', $this->user['pid1']);
if ($order['puid1'] == $this->uuid) $order['puid1'] = 0;
if ($order['puid1'] > 0) {
$map = ['id' => $order['puid1'], 'status' => 1];
$order['puid2'] = DataUser::mk()->where($map)->value('pid2');
if (is_null($order['puid2'])) $this->error('代理异常');
}
// 订单商品处理
foreach (explode('||', $rules) as $rule) {
[$code, $spec, $count] = explode('@', $rule);
// 商品信息检查
$goodsInfo = ShopGoods::mk()->where(['code' => $code, 'status' => 1, 'deleted' => 0])->find();
$goodsItem = ShopGoodsItem::mk()->where(['status' => 1, 'goods_code' => $code, 'goods_spec' => $spec])->find();
if (empty($goodsInfo) || empty($goodsItem)) $this->error('商品查询异常');
// 商品类型检查
if ($truckType < 0) $truckType = $goodsInfo['truck_type'];
if ($truckType !== $goodsInfo['truck_type']) $this->error('不能混合下单');
// 限制购买数量
if (isset($goodsInfo['limit_max_num']) && $goodsInfo['limit_max_num'] > 0) {
$map = [['a.uuid', '=', $this->uuid], ['a.status', 'in', [2, 3, 4, 5]], ['b.goods_code', '=', $goodsInfo['code']]];
$buys = ShopOrder::mk()->alias('a')->join('store_order_item b', 'a.order_no=b.order_no')->where($map)->sum('b.stock_sales');
if ($buys + $count > $goodsInfo['limit_max_num']) $this->error('超过限购数量');
}
// 限制购买身份
if ($goodsInfo['limit_low_vip'] > $this->user['vip_code']) $this->error('用户等级不够');
// 商品库存检查
if ($goodsItem['stock_sales'] + $count > $goodsItem['stock_total']) $this->error('商品库存不足');
// 支付支付处理
$_allowPayments = [];
foreach (str2arr($goodsInfo['payment']) as $code) {
if (is_null($allowPayments) || in_array($code, $allowPayments)) $_allowPayments[] = $code;
}
if (empty($_allowPayments)) {
$this->error('订单无法统一支付');
} else {
$allowPayments = $_allowPayments;
}
// 商品折扣处理
[$discountId, $discountRate] = OrderService::discount($goodsInfo['discount_id'], $this->user['vip_code']);
// 订单详情处理
$items[] = [
'uuid' => $order['uuid'],
'order_no' => $order['order_no'],
// 商品信息字段
'goods_name' => $goodsInfo['name'],
'goods_cover' => $goodsInfo['cover'],
'goods_payment' => $goodsInfo['payment'],
'goods_sku' => $goodsItem['goods_sku'],
'goods_code' => $goodsItem['goods_code'],
'goods_spec' => $goodsItem['goods_spec'],
// 库存数量处理
'stock_sales' => $count,
// 快递发货数据
'truck_type' => $goodsInfo['truck_type'],
'truck_code' => $goodsInfo['truck_code'],
'truck_number' => $goodsInfo['rebate_type'] > 0 ? $goodsItem['number_express'] * $count : 0,
// 商品费用字段
'price_market' => $goodsItem['price_market'],
'price_selling' => $goodsItem['price_selling'],
'total_market' => $goodsItem['price_market'] * $count,
'total_selling' => $goodsItem['price_selling'] * $count,
// 奖励金额积分
'reward_balance' => $goodsItem['reward_balance'] * $count,
'reward_integral' => $goodsItem['reward_integral'] * $count,
// 绑定用户等级
'vip_name' => $this->user['vip_name'],
'vip_code' => $this->user['vip_code'],
// 是否入会礼包
'vip_entry' => $goodsInfo['vip_entry'],
'vip_upgrade' => $goodsInfo['vip_upgrade'],
// 是否参与返利
'rebate_type' => $goodsInfo['rebate_type'],
'rebate_amount' => $goodsInfo['rebate_type'] > 0 ? $goodsItem['price_selling'] * $count : 0,
// 等级优惠方案
'discount_id' => $discountId,
'discount_rate' => $discountRate,
'discount_amount' => $discountRate * $goodsItem['price_selling'] * $count / 100,
];
}
try {
$order['payment_allow'] = arr2str($allowPayments);
$order['rebate_amount'] = array_sum(array_column($items, 'rebate_amount'));
$order['reward_balance'] = array_sum(array_column($items, 'reward_balance'));
// 订单发货类型
$order['status'] = $truckType ? 1 : 2;
$order['truck_type'] = $truckType;
// 统计商品数量
$order['number_goods'] = array_sum(array_column($items, 'stock_sales'));
$order['number_express'] = array_sum(array_column($items, 'truck_number'));
// 统计商品金额
$order['amount_goods'] = array_sum(array_column($items, 'total_selling'));
// 优惠后的金额
$order['amount_discount'] = array_sum(array_column($items, 'discount_amount'));
// 订单随机免减
$order['amount_reduct'] = OrderService::getReduct();
if ($order['amount_reduct'] > $order['amount_goods']) {
$order['amount_reduct'] = $order['amount_goods'];
}
// 统计订单金额
$order['amount_real'] = $order['amount_discount'] - $order['amount_reduct'];
$order['amount_total'] = $order['amount_goods'];
// 写入商品数据
$this->app->db->transaction(function () use ($order, $items) {
ShopOrder::mk()->insert($order);
ShopOrderItem::mk()->insertAll($items);
});
// 同步商品库存销量
foreach (array_unique(array_column($items, 'goods_code')) as $code) {
GoodsService::stock($code);
}
// 触发订单创建事件
$this->app->event->trigger('ShopOrderCreate', $order['order_no']);
// 组装订单商品数据
$order['items'] = $items;
// 返回处理成功数据
$this->success('商品下单成功', $order);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error("商品下单失败,{$exception->getMessage()}");
}
}
/**
* 获取用户折扣
*/
public function discount()
{
$data = $this->_vali(['discount.require' => '折扣编号不能为空!']);
[, $rate] = OrderService::discount(intval($data['discount']), $this->user['vip_code']);
$this->success('获取用户折扣', ['rate' => $rate]);
}
/**
* 模拟计算订单运费
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function express()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空',
'order_no.require' => '单号不能为空',
]);
// 用户收货地址
$map = ['uuid' => $this->uuid, 'code' => $data['code']];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('收货地址异常');
// 订单状态检查
$map = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
$tCount = ShopOrderItem::mk()->where($map)->sum('truck_number');
// 根据地址计算运费
$map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
$tCode = ShopOrderItem::mk()->where($map)->column('truck_code');
[$amount, , , $remark] = ExpressService::amount($tCode, $addr['province'], $addr['city'], $tCount);
$this->success('计算运费成功', ['amount' => $amount, 'remark' => $remark]);
}
/**
* 订单信息完成
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function perfect()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'code.require' => '地址不能为空',
'order_no.require' => '单号不能为空',
]);
// 用户收货地址
$map = ['uuid' => $this->uuid, 'code' => $data['code'], 'deleted' => 0];
$addr = DataUserAddress::mk()->where($map)->find();
if (empty($addr)) $this->error('收货地址异常');
// 订单状态检查
$map1 = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
$order = ShopOrder::mk()->where($map1)->whereIn('status', [1, 2])->find();
if (empty($order)) $this->error('不能修改地址');
if (empty($order['truck_type'])) $this->success('无需快递配送', ['order_no' => $order['order_no']]);
// 根据地址计算运费
$map2 = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
$tCount = ShopOrderItem::mk()->where($map1)->sum('truck_number');
$tCodes = ShopOrderItem::mk()->where($map2)->column('truck_code');
[$amount, $tCount, $tCode, $remark] = ExpressService::amount($tCodes, $addr['province'], $addr['city'], $tCount);
// 创建订单发货信息
$express = [
'template_code' => $tCode, 'template_count' => $tCount, 'uuid' => $this->uuid,
'template_remark' => $remark, 'template_amount' => $amount, 'status' => 1,
];
$express['order_no'] = $data['order_no'];
$express['address_code'] = $data['code'];
$express['address_datetime'] = date('Y-m-d H:i:s');
// 收货人信息
$express['address_name'] = $addr['name'];
$express['address_phone'] = $addr['phone'];
$express['address_idcode'] = $addr['idcode'];
$express['address_idimg1'] = $addr['idimg1'];
$express['address_idimg2'] = $addr['idimg2'];
// 收货地址信息
$express['address_province'] = $addr['province'];
$express['address_city'] = $addr['city'];
$express['address_area'] = $addr['area'];
$express['address_content'] = $addr['address'];
ShopOrderSend::mUpdate($express, 'order_no');
data_save(ShopOrderSend::class, $express, 'order_no');
// 组装更新订单数据
$update = ['status' => 2, 'amount_express' => $express['template_amount']];
// 重新计算订单金额
$update['amount_real'] = $order['amount_discount'] + $amount - $order['amount_reduct'];
$update['amount_total'] = $order['amount_goods'] + $amount;
// 支付金额不能为零
if ($update['amount_real'] <= 0) $update['amount_real'] = 0.00;
if ($update['amount_total'] <= 0) $update['amount_total'] = 0.00;
// 更新用户订单数据
$map = ['uuid' => $this->uuid, 'order_no' => $data['order_no']];
if (ShopOrder::mk()->where($map)->update($update) !== false) {
// 触发订单确认事件
$this->app->event->trigger('ShopOrderPerfect', $order['order_no']);
// 返回处理成功数据
$this->success('订单确认成功', ['order_no' => $order['order_no']]);
} else {
$this->error('订单确认失败');
}
}
/**
* 获取支付支付数据
*/
public function channel()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'order_no.require' => '单号不能为空']);
$payments = ShopOrder::mk()->where($data)->value('payment_allow');
if (empty($payments)) $this->error('获取订单支付参数失败');
// 读取支付通道配置
$query = BaseUserPayment::mk()->where(['status' => 1, 'deleted' => 0]);
$query->whereIn('code', str2arr($payments))->whereIn('type', PaymentService::getTypeApi($this->type));
$result = $query->order('sort desc,id desc')->column('type,code,name,cover,content,remark', 'code');
foreach ($result as &$vo) $vo['content'] = ['voucher_qrcode' => json_decode($vo['content'])->voucher_qrcode ?? ''];
$this->success('获取支付参数数据', array_values($result));
}
/**
* 获取订单支付状态
* @throws \think\db\exception\DbException
*/
public function payment()
{
$data = $this->_vali([
'uuid.value' => $this->uuid,
'order_no.require' => '单号不能为空',
'order_remark.default' => '',
'payment_code.require' => '支付不能为空',
'payment_back.default' => '', # 支付回跳地址
'payment_image.default' => '', # 支付凭证图片
]);
[$map, $order] = $this->getOrderData();
if ($order['status'] !== 2) $this->error('不能发起支付');
if ($order['payment_status'] > 0) $this->error('已经完成支付');
// 更新订单备注
if (!empty($data['order_remark'])) {
ShopOrder::mk()->where($map)->update([
'order_remark' => $data['order_remark'],
]);
}
// 自动处理用户字段
$openid = '';
if (in_array($this->type, [UserAdminService::API_TYPE_WXAPP, UserAdminService::API_TYPE_WECHAT])) {
$openid = $this->user[UserAdminService::TYPES[$this->type]['auth']] ?? '';
if (empty($openid)) $this->error("发起支付失败");
}
try {
// 返回订单数据及支付发起参数
$type = $order['amount_real'] <= 0 ? 'empty' : $data['payment_code'];
$param = PaymentService::instance($type)->create($openid, $order['order_no'], $order['amount_real'], '商城订单支付', '', $data['payment_back'], $data['payment_image']);
$this->success('获取支付参数', ['order' => ShopOrder::mk()->where($map)->find() ?: new \stdClass(), 'param' => $param]);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
/**
* 主动取消未支付的订单
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cancel()
{
[$map, $order] = $this->getOrderData();
if (in_array($order['status'], [1, 2, 3])) {
$result = ShopOrder::mk()->where($map)->update([
'status' => 0,
'cancel_status' => 1,
'cancel_remark' => '用户主动取消订单',
'cancel_datetime' => date('Y-m-d H:i:s'),
]);
if ($result !== false && OrderService::stock($order['order_no'])) {
// 触发订单取消事件
$this->app->event->trigger('ShopOrderCancel', $order['order_no']);
// 返回处理成功数据
$this->success('订单取消成功');
} else {
$this->error('订单取消失败');
}
} else {
$this->error('订单不可取消');
}
}
/**
* 用户主动删除已取消的订单
* @throws \think\db\exception\DbException
*/
public function remove()
{
[$map, $order] = $this->getOrderData();
if (empty($order)) $this->error('读取订单失败');
if ($order['status'] == 0) {
$result = ShopOrder::mk()->where($map)->update([
'status' => 0,
'deleted_status' => 1,
'deleted_remark' => '用户主动删除订单',
'deleted_datetime' => date('Y-m-d H:i:s'),
]);
if ($result !== false) {
// 触发订单删除事件
$this->app->event->trigger('ShopOrderRemove', $order['order_no']);
// 返回处理成功数据
$this->success('订单删除成功');
} else {
$this->error('订单删除失败');
}
} else {
$this->error('订单不可删除');
}
}
/**
* 订单确认收货
* @throws \think\db\exception\DbException
*/
public function confirm()
{
[$map, $order] = $this->getOrderData();
if ($order['status'] == 5) {
if (ShopOrder::mk()->where($map)->update(['status' => 6]) !== false) {
// 触发订单确认事件
$this->app->event->trigger('ShopOrderConfirm', $order['order_no']);
// 返回处理成功数据
$this->success('订单确认成功');
} else {
$this->error('订单确认失败');
}
} else {
$this->error('订单确认失败');
}
}
/**
* 获取输入订单
* @return array [map, order]
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getOrderData(): array
{
$map = $this->_vali([
'uuid.value' => $this->uuid,
'order_no.require' => '单号不能为空',
]);
$order = ShopOrder::mk()->where($map)->find();
if (empty($order)) $this->error('读取订单失败');
return [$map, $order];
}
/**
* 订单状态统计
*/
public function total()
{
$data = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0];
$query = ShopOrder::mk()->where(['uuid' => $this->uuid, 'deleted_status' => 0]);
foreach ($query->field('status,count(1) count')->group('status')->cursor() as $item) {
$data["t{$item['status']}"] = $item['count'];
}
$this->success('获取订单统计', $data);
}
/**
* 物流追踪查询
*/
public function track()
{
try {
$data = $this->_vali([
'code.require' => '快递不能为空',
'number.require' => '单号不能为空'
]);
$result = ExpressService::query($data['code'], $data['number']);
empty($result['code']) ? $this->error($result['info']) : $this->success('快递追踪信息', $result);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -1,58 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\BaseUserUpgrade;
use app\data\model\DataUserRebate;
use app\data\service\RebateService;
/**
* 用户返利管理
* Class Rebate
* @package app\data\controller\api\auth
*/
class Rebate extends Auth
{
/**
* 获取用户返利记录
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$date = trim(input('date', date('Y-m')), '-');
[$map, $year] = [['uuid' => $this->uuid], substr($date, 0, 4)];
$query = DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$date}%");
$this->success('获取返利统计', array_merge($query->order('id desc')->page(true, false, false, 10), [
'total' => [
'年度' => DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$year}%")->db()->sum('amount'),
'月度' => DataUserRebate::mQuery()->where($map)->equal('type,status')->whereLike('date', "{$date}%")->db()->sum('amount'),
],
]));
}
/**
* 获取我的奖励
*/
public function prize()
{
[$map, $data] = [['number' => $this->user['vip_code']], []];
$prizes = DataUserRebate::mk()->group('name')->column('name');
$rebate = BaseUserUpgrade::mk()->where($map)->value('rebate_rule', '');
$codemap = array_merge($prizes, str2arr($rebate));
foreach (RebateService::PRIZES as $prize) {
if (in_array($prize['code'], $codemap)) $data[] = $prize;
}
$this->success('获取我的奖励', $data);
}
/**
* 获取奖励配置
*/
public function prizes()
{
$this->success('获取系统奖励', array_values(RebateService::PRIZES));
}
}

View File

@ -1,162 +0,0 @@
<?php
namespace app\data\controller\api\auth;
use app\data\controller\api\Auth;
use app\data\model\DataUserTransfer;
use app\data\service\UserRebateService;
use app\data\service\UserTransferService;
use think\admin\extend\CodeExtend;
/**
* 用户提现接口
* Class Transfer
* @package app\data\controller\api\auth
*/
class Transfer extends Auth
{
/**
* 提交提现处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add()
{
// 检查用户状态
$this->checkUserStatus();
// 接收输入数据
$data = $this->_vali([
'type.require' => '提现方式不能为空!',
'amount.require' => '提现金额不能为空!',
'remark.default' => '用户提交提现申请!',
]);
$state = UserTransferService::config('status');
if (empty($state)) $this->error('提现还没有开启!');
$transfers = UserTransferService::config('transfer');
if (empty($transfers[$data['type']]['state'])) $this->error('提现方式已停用!');
// 提现数据补充
$data['uuid'] = $this->uuid;
$data['date'] = date('Y-m-d');
$data['code'] = CodeExtend::uniqidDate(20, 'T');
// 提现状态处理
if (empty($transfers[$data['type']]['state']['audit'])) {
$data['status'] = 1;
$data['audit_status'] = 0;
} else {
$data['status'] = 3;
$data['audit_status'] = 1;
$data['audit_remark'] = '提现免审核';
$data['audit_datetime'] = date('Y-m-d H:i:s');
}
// 扣除手续费
$chargeRate = floatval(UserTransferService::config('charge'));
$data['charge_rate'] = $chargeRate;
$data['charge_amount'] = $chargeRate * $data['amount'] / 100;
// 检查可提现余额
[$total, $count] = UserRebateService::amount($this->uuid);
if ($total - $count < $data['amount']) $this->error('可提现余额不足!');
// 提现方式处理
if ($data['type'] == 'alipay_account') {
$data = array_merge($data, $this->_vali([
'alipay_user.require' => '开户姓名不能为空!',
'alipay_code.require' => '支付账号不能为空!',
]));
} elseif (in_array($data['type'], ['wechat_qrcode', 'alipay_qrcode'])) {
$data = array_merge($data, $this->_vali([
'qrcode.require' => '收款码不能为空!',
]));
} elseif (in_array($data['type'], ['wechat_banks', 'transfer_banks'])) {
$data = array_merge($data, $this->_vali([
'bank_wseq.require' => '银行编号不能为空!',
'bank_name.require' => '银行名称不能为空!',
'bank_user.require' => '开户账号不能为空!',
'bank_bran.require' => '银行分行不能为空!',
'bank_code.require' => '银行卡号不能为空!',
]));
} elseif ($data['type'] != 'wechat_wallet') {
$this->error('转账方式不存在!');
}
// 当日提现次数限制
$map = ['uuid' => $this->uuid, 'type' => $data['type'], 'date' => $data['date']];
$count = DataUserTransfer::mk()->where($map)->count();
if ($count >= $transfers[$data['type']]['dayNumber']) $this->error("当日提现次数受限");
// 提现金额范围控制
if ($transfers[$data['type']]['minAmount'] > $data['amount']) {
$this->error("不能少于{$transfers[$data['type']]['minAmount']}");
}
if ($transfers[$data['type']]['maxAmount'] < $data['amount']) {
$this->error("不能大于{$transfers[$data['type']]['maxAmount']}");
}
// 写入用户提现数据
if (DataUserTransfer::mk()->insert($data) !== false) {
UserRebateService::amount($this->uuid);
$this->success('提现申请成功');
} else {
$this->error('提现申请失败');
}
}
/**
* 用户提现记录
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function get()
{
$query = DataUserTransfer::mQuery()->where(['uuid' => $this->uuid]);
$result = $query->like('date,code')->in('status')->order('id desc')->page(true, false, false, 10);
// 统计历史数据
$map = [['uuid', '=', $this->uuid], ['status', '>', 0]];
[$total, $count, $locks] = UserRebateService::amount($this->uuid);
$this->success('获取提现成功', array_merge($result, [
'total' => [
'锁定' => $locks,
'可提' => $total - $count,
'上月' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-m-%", strtotime('-1 month')))->sum('amount'),
'本月' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-m-%"))->sum('amount'),
'全年' => DataUserTransfer::mk()->where($map)->whereLike('date', date("Y-%"))->sum('amount'),
],
]));
}
/**
* 用户取消提现
*/
public function cancel()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'code.require' => '单号不能为空!']);
DataUserTransfer::mk()->where($data)->whereIn('status', [1, 2, 3])->update([
'status' => 0, 'change_time' => date("Y-m-d H:i:s"), 'change_desc' => '用户主动取消提现',
]);
UserRebateService::amount($this->uuid);
$this->success('取消提现成功');
}
/**
* 用户确认提现
*/
public function confirm()
{
$data = $this->_vali(['uuid.value' => $this->uuid, 'code.require' => '单号不能为空!']);
DataUserTransfer::mk()->where($data)->whereIn('status', [4])->update([
'status' => 5, 'change_time' => date("Y-m-d H:i:s"), 'change_desc' => '用户主动确认收款',
]);
UserRebateService::amount($this->uuid);
$this->success('确认收款成功');
}
/**
* 获取用户提现配置
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function config()
{
$data = UserTransferService::config();
$data['banks'] = UserTransferService::instance()->banks();
$this->success('获取用户提现配置', $data);
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace app\data\controller\base;
use think\admin\Controller;
/**
* 应用参数配置
* Class Config
* @package app\data\controller\base
*/
class Config extends Controller
{
/**
* 微信小程序配置
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function wxapp()
{
$this->skey = 'wxapp';
$this->title = '微信小程序配置';
$this->__sysdata('wxapp');
}
/**
* 邀请二维码设置
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cropper()
{
$this->skey = 'cropper';
$this->title = '邀请二维码设置';
$this->__sysdata('cropper');
}
/**
* 显示并保存数据
* @param string $template 模板文件
* @param string $history 跳转处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function __sysdata(string $template, string $history = '')
{
if ($this->request->isGet()) {
$this->data = sysdata($this->skey);
$this->fetch($template);
}
if ($this->request->isPost()) {
if (is_string(input('data'))) {
$data = json_decode(input('data'), true) ?: [];
} else {
$data = $this->request->post();
}
if (sysdata($this->skey, $data) !== false) {
$this->success('内容保存成功!', $history);
} else {
$this->error('内容保存失败,请稍候再试!');
}
}
}
}

View File

@ -1,93 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserDiscount;
use app\data\model\BaseUserUpgrade;
use app\data\service\UserUpgradeService;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
/**
* 折扣方案管理
* Class Discount
* @package app\data\controller\base
*/
class Discount extends Controller
{
/**
* 折扣方案管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = input('get.type', 'index');
BaseUserDiscount::mQuery()->layTable(function () {
$this->title = '折扣方案管理';
}, function (QueryHelper $query) {
$query->where(['status' => intval($this->type === 'index'), 'deleted' => 0]);
});
}
/**
* 添加折扣方案
* @auth true
*/
public function add()
{
BaseUserDiscount::mForm('form');
}
/**
* 编辑折扣方案
* @auth true
*/
public function edit()
{
BaseUserDiscount::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isPost()) {
$rule = [];
foreach ($vo as $k => $v) if (stripos($k, '_level_') !== false) {
[, $level] = explode('_level_', $k);
$rule[] = ['level' => $level, 'discount' => $v];
}
$vo['items'] = json_encode($rule, JSON_UNESCAPED_UNICODE);
} else {
$this->levels = BaseUserUpgrade::items();
if (empty($this->levels)) $this->error('未配置用户等级!');
foreach ($vo['items'] ?? [] as $item) {
$vo["_level_{$item['level']}"] = $item['discount'];
}
}
}
/**
* 修改折扣方案状态
* @auth true
*/
public function state()
{
BaseUserDiscount::mSave();
}
/**
* 删除折扣方案配置
* @auth true
*/
public function remove()
{
BaseUserDiscount::mDelete();
}
}

View File

@ -1,85 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserMessage;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
/**
* 系统通知管理
* Class Notify
* @package app\data\controller\base
*/
class Message extends Controller
{
/**
* 系统通知管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
BaseUserMessage::mQuery()->layTable(function () {
$this->title = '系统通知管理';
}, function (QueryHelper $query) {
$query->where(['deleted' => 0]);
$query->like('name')->equal('status')->dateBetween('create_at');
});
}
/**
* 添加系统通知
* @auth true
*/
public function add()
{
$this->title = '添加系统通知';
BaseUserMessage::mForm('form');
}
/**
* 编辑系统通知
* @auth true
*/
public function edit()
{
$this->title = '编辑系统通知';
BaseUserMessage::mForm('form');
}
/**
* 表单结果处理
* @param boolean $state
*/
protected function _form_result(bool $state)
{
if ($state) {
$this->success('内容保存成功!', 'javascript:history.back()');
}
}
/**
* 修改通知状态
* @auth true
*/
public function state()
{
BaseUserMessage::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除系统通知
* @auth true
*/
public function remove()
{
BaseUserMessage::mDelete();
}
}

View File

@ -1,87 +0,0 @@
<?php
namespace app\data\controller\base;
use think\admin\Controller;
use think\admin\model\SystemBase;
/**
* 页面内容管理
* Class Pager
* @package app\data\controller\base
*/
class Pager extends Controller
{
/**
* 字典类型
* @var string
*/
protected $type = '页面内容';
/**
* 页面类型
* @var array
*/
protected $types = [];
/**
* 控制器初始化
* @return void
*/
protected function initialize()
{
$this->types = SystemBase::mk()->items($this->type);
}
/**
* 内容页面管理
* @auth true
* @menu true
*/
public function index()
{
$this->title = '内容页面管理';
$this->fetch();
}
/**
* 内容页面编辑
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit()
{
$this->skey = input('get.type', '');
$this->base = $this->types[$this->skey] ?? [];
if (empty($this->base)) $this->error('未配置基础数据!');
$this->title = "编辑{$this->base['name']}";
$this->sysdata();
}
/**
* 显示并保存数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function sysdata()
{
if ($this->request->isGet()) {
$this->data = sysdata($this->skey);
$this->fetch('form');
} elseif ($this->request->isPost()) {
if (is_string(input('data'))) {
$data = json_decode(input('data'), true) ?: [];
} else {
$data = $this->request->post();
}
if (sysdata($this->skey, $data) !== false) {
$this->success('内容保存成功!', 'javascript:history.back()');
} else {
$this->error('内容保存失败,请稍候再试!');
}
}
}
}

View File

@ -1,134 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserPayment;
use app\data\service\PaymentService;
use app\data\service\UserAdminService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\helper\QueryHelper;
/**
* 支付通道管理
* Class Payment
* @package app\data\controller\base
*/
class Payment extends Controller
{
/**
* 支付通道类型
* @var array
*/
protected $types = PaymentService::TYPES;
/**
* 支付通道管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = input('get.type', 'index');
BaseUserPayment::mQuery()->layTable(function () {
$this->title = '支付通道管理';
}, function (QueryHelper $query) {
$query->where(['status' => intval($this->type === 'index'), 'deleted' => 0]);
$query->like('name,code')->equal('status,type#ptype')->dateBetween('create_at');
});
}
/**
* 获取支付名称
* @param array $data
* @return void
*/
protected function _page_filter(array &$data)
{
foreach ($data as &$vo) {
$vo['ntype'] = $this->types[$vo['type']]['name'] ?? $vo['type'];
}
}
/**
* 添加支付通道
* @auth true
*/
public function add()
{
$this->title = '添加支付通道';
BaseUserPayment::mForm('form');
}
/**
* 编辑支付通道
* @auth true
*/
public function edit()
{
$this->title = '编辑支付通道';
BaseUserPayment::mForm('form');
}
/**
* 数据表单处理
* @param array $data
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(20, 'M');
}
if ($this->request->isGet()) {
$this->payments = [];
foreach ($this->types as $k => $vo) {
$allow = [];
foreach ($vo['bind'] as $api) if (isset(UserAdminService::TYPES[$api])) {
$allow[$api] = UserAdminService::TYPES[$api]['name'];
}
if (empty($allow)) continue;
$this->payments[$k] = array_merge($vo, ['allow' => join('、', $allow)]);
}
$data['content'] = json_decode($data['content'] ?? '[]', true) ?: [];
} else {
if (empty($data['type'])) $this->error('请选择支付通道并配置参数!');
if (empty($data['cover'])) $this->error('请上传支付方式图标!');
$data['content'] = json_encode($this->request->post() ?: [], JSON_UNESCAPED_UNICODE);
}
}
/**
* 表单结果处理
* @param boolean $state
*/
protected function _form_result(bool $state)
{
if ($state) {
$this->success('支付通道保存成功!', 'javascript:history.back()');
}
}
/**
* 修改通道状态
* @auth true
*/
public function state()
{
BaseUserPayment::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除支付通道
* @auth true
*/
public function remove()
{
BaseUserPayment::mDelete();
}
}

View File

@ -1,102 +0,0 @@
<?php
namespace app\data\controller\base;
use think\admin\Controller;
use think\admin\model\SystemBase;
/**
* 图片内容管理
* Class Slider
* @package app\data\controller\base
*/
class Slider extends Controller
{
/**
* 跳转规则定义
* @var string[]
*/
protected $rules = [
'#' => ['name' => '不跳转'],
'LK' => ['name' => '自定义链接'],
'NL' => ['name' => '新闻资讯列表'],
'NS' => ['name' => '新闻资讯详情', 'node' => 'data/news.item/select'],
];
/**
* 数据类型
* @var string
*/
protected $type = '图片内容';
/**
* 页面类型
* @var array
*/
protected $types = [];
/**
* 控制器初始化
* @return void
*/
protected function initialize()
{
$this->types = SystemBase::mk()->items($this->type);
foreach ($this->types as &$type) {
if (preg_match('/^(.*?)#(\d+)$/', $type['name'], $matches)) {
$type['name'] = $matches[1];
$type['number'] = $matches[2];
} else {
$type['number'] = 0;
}
}
}
/**
* 图片内容管理
* @auth true
* @menu true
*/
public function index()
{
$this->title = '图片内容管理';
$this->fetch();
}
/**
* 编辑图片内容
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit()
{
$this->skey = input('get.type', '');
$this->base = $this->types[$this->skey] ?? [];
if (empty($this->base)) $this->error('未配置基础数据!');
$this->number = $this->base['number'];
$this->sysdata();
}
/**
* 保存图片内容
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function sysdata()
{
if ($this->request->isGet()) {
$this->data = sysdata($this->skey);
$this->title = "{$this->base['name']}管理";
$this->fetch('form');
} else {
if (sysdata($this->skey, json_decode(input('data'), true))) {
$this->success("{$this->base['name']}保存成功!");
} else {
$this->error("{$this->base['name']}保存失败,请稍候再试!");
}
}
}
}

View File

@ -1,156 +0,0 @@
<?php
namespace app\data\controller\base;
use app\data\model\BaseUserUpgrade;
use app\data\service\RebateService;
use think\admin\Controller;
/**
* 用户等级管理
* Class Upgrade
* @package app\data\controller\base
*/
class Upgrade extends Controller
{
/**
* 用户等级管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '用户等级管理';
BaseUserUpgrade::mQuery()->like('name')->equal('status')->dateBetween('create_at')->layTable();
}
/**
* 添加用户等级
* @auth true
* @return void
* @throws \think\db\exception\DbException
*/
public function add()
{
$this->max = BaseUserUpgrade::maxNumber() + 1;
BaseUserUpgrade::mForm('form');
}
/**
* 编辑用户等级
* @auth true
* @return void
* @throws \think\db\exception\DbException
*/
public function edit()
{
$this->max = BaseUserUpgrade::maxNumber();
BaseUserUpgrade::mForm('form');
}
/**
* 表单数据处理
* @param array $vo
* @throws \think\db\exception\DbException
*/
protected function _form_filter(array &$vo)
{
if ($this->request->isGet()) {
$this->prizes = RebateService::PRIZES;
$vo['number'] = $vo['number'] ?? BaseUserUpgrade::maxNumber();
} else {
$vo['utime'] = time();
// 用户升级条件开关
$vo['goods_vip_status'] = isset($vo['goods_vip_status']) ? 1 : 0;
$vo['teams_users_status'] = isset($vo['teams_users_status']) ? 1 : 0;
$vo['teams_direct_status'] = isset($vo['teams_direct_status']) ? 1 : 0;
$vo['teams_indirect_status'] = isset($vo['teams_indirect_status']) ? 1 : 0;
$vo['order_amount_status'] = isset($vo['order_amount_status']) ? 1 : 0;
// 默认等级去除条件
if (empty($vo['number'])) {
$vo['rebate_rule'] = [];
foreach ($vo as $k => &$v) if (is_numeric(stripos($k, '_status'))) $v = 0;
}
// 根据数量判断状态
$vo['teams_users_status'] = intval($vo['teams_users_status'] && $vo['teams_users_number'] > 0);
$vo['teams_direct_status'] = intval($vo['teams_direct_status'] && $vo['teams_direct_number'] > 0);
$vo['teams_indirect_status'] = intval($vo['teams_indirect_status'] && $vo['teams_indirect_number'] > 0);
$vo['order_amount_status'] = intval($vo['order_amount_status'] && $vo['order_amount_number'] > 0);
// 检查升级条件配置
$count = 0;
foreach ($vo as $k => $v) if (is_numeric(stripos($k, '_status'))) $count += $v;
if (empty($count) && $vo['number'] > 0) $this->error('升级条件不能为空!');
}
}
/**
* 表单结果处理
* @param boolean $state
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function _form_result(bool $state)
{
if ($state) {
$isasc = input('old_number', 0) <= input('number', 0);
$order = $isasc ? 'number asc,utime asc' : 'number asc,utime desc';
foreach (BaseUserUpgrade::mk()->order($order)->select() as $number => $upgrade) {
$upgrade->save(['number' => $number]);
}
}
}
/**
* 重算用户等级
* @auth true
*/
public function sync()
{
$this->_queue('重新计算所有用户等级', 'xdata:UserUpgrade');
}
/**
* 修改等级状态
* @auth true
*/
public function state()
{
BaseUserUpgrade::mSave();
}
/**
* 删除用户等级
* @auth true
*/
public function remove()
{
BaseUserUpgrade::mDelete();
}
/**
* 状态变更处理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _save_result()
{
$this->_form_result(true);
}
/**
* 删除结果处理
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _delete_result()
{
$this->_form_result(true);
}
}

View File

@ -1,115 +0,0 @@
<?php
namespace app\data\controller\base\postage;
use app\data\model\BasePostageCompany;
use app\data\service\ExpressService;
use think\admin\Controller;
use think\admin\helper\QueryHelper;
use think\exception\HttpResponseException;
/**
* 快递公司管理
* Class Company
* @package app\data\controller\base\postage
*/
class Company extends Controller
{
/**
* 快递公司管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = input('get.type', 'index');
BasePostageCompany::mQuery()->layTable(function () {
$this->title = '快递公司管理';
}, function (QueryHelper $query) {
$query->where(['deleted' => 0, 'status' => intval($this->type === 'index')]);
$query->like('name,code_1|code_3#code')->equal('status')->dateBetween('create_at');
});
}
/**
* 添加快递公司
* @auth true
*/
public function add()
{
$this->title = '添加快递公司';
BasePostageCompany::mForm('form');
}
/**
* 编辑快递公司
* @auth true
*/
public function edit()
{
$this->title = '编辑快递公司';
BasePostageCompany::mForm('form');
}
/**
* 同步字段编号
* @param array $data
* @return void
*/
protected function _form_filter(array &$data)
{
if ($this->request->isPost()) {
if (empty($data['code_2'])) {
$data['code_2'] = $data['code_3'];
}
}
}
/**
* 修改快递公司状态
* @auth true
*/
public function state()
{
BasePostageCompany::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除快递公司
* @auth true
*/
public function remove()
{
BasePostageCompany::mDelete();
}
/**
* 同步快递公司
* @auth true
*/
public function sync()
{
try {
$result = ExpressService::company();
if (empty($result['code'])) $this->error($result['info']);
foreach ($result['data'] as $vo) BasePostageCompany::mUpdate([
'name' => $vo['title'],
'code_1' => $vo['code_1'],
'code_2' => $vo['code_2'],
'code_3' => $vo['code_3'],
'deleted' => 0,
], 'code_1');
$this->success('同步快递公司成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error('同步快递公司数据失败!');
}
}
}

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