Browse Source

租房掌柜微信小程序Api以及前端小程序模板

master
ahbmz 4 years ago
commit
3b5ce47f81
  1. 8
      .idea/.gitignore
  2. 5
      .idea/inspectionProfiles/profiles_settings.xml
  3. 8
      .idea/modules.xml
  4. 6
      .idea/vcs.xml
  5. 8
      .idea/xunxibaoapi.yaoyz.com.iml
  6. 21
      LICENSE
  7. 131
      README.md
  8. 790
      admin_v5.sql
  9. 180
      application/admin/controller/Auth.php
  10. 108
      application/admin/controller/Config.php
  11. 177
      application/admin/controller/Index.php
  12. 124
      application/admin/controller/Login.php
  13. 162
      application/admin/controller/Menu.php
  14. 94
      application/admin/controller/Oplog.php
  15. 97
      application/admin/controller/Queue.php
  16. 176
      application/admin/controller/User.php
  17. 100
      application/admin/controller/api/Plugs.php
  18. 60
      application/admin/controller/api/Update.php
  19. 124
      application/admin/queue/JobsQueue.php
  20. 346
      application/admin/service/NodeService.php
  21. 53
      application/admin/service/OplogService.php
  22. 130
      application/admin/service/QueueService.php
  23. 119
      application/admin/sys.php
  24. 3659
      application/admin/view/api/plugs/icon.html
  25. 116
      application/admin/view/auth/apply.html
  26. 22
      application/admin/view/auth/form.html
  27. 80
      application/admin/view/auth/index.html
  28. 42
      application/admin/view/auth/index_search.html
  29. 21
      application/admin/view/config/info-storage-local.html
  30. 79
      application/admin/view/config/info-storage-oss.html
  31. 80
      application/admin/view/config/info-storage-qiniu.html
  32. 32
      application/admin/view/config/info-storage.html
  33. 54
      application/admin/view/config/info-website.html
  34. 29
      application/admin/view/config/info.html
  35. 125
      application/admin/view/index/index.html
  36. 207
      application/admin/view/index/main.html
  37. 50
      application/admin/view/login/index.html
  38. 11
      application/admin/view/main.html
  39. 88
      application/admin/view/menu/form.html
  40. 80
      application/admin/view/menu/index.html
  41. 67
      application/admin/view/oplog/index.html
  42. 56
      application/admin/view/oplog/index_search.html
  43. 79
      application/admin/view/queue/index.html
  44. 68
      application/admin/view/queue/index_search.html
  45. 63
      application/admin/view/user/form.html
  46. 77
      application/admin/view/user/index.html
  47. 57
      application/admin/view/user/index_search.html
  48. 53
      application/admin/view/user/pass.html
  49. 2
      application/api/common.php
  50. 41
      application/api/controller/Base.php
  51. 166
      application/api/controller/Sms.php
  52. 33
      application/api/validate/Sms.php
  53. 122
      application/index/common.php
  54. 42
      application/index/controller/Ad.php
  55. 212
      application/index/controller/Base.php
  56. 269
      application/index/controller/Clean.php
  57. 73
      application/index/controller/Collection.php
  58. 46
      application/index/controller/Config.php
  59. 105
      application/index/controller/Contract.php
  60. 137
      application/index/controller/Crontab.php
  61. 580
      application/index/controller/House.php
  62. 193
      application/index/controller/Index.php
  63. 106
      application/index/controller/Login.php
  64. 238
      application/index/controller/Member.php
  65. 67
      application/index/controller/Notify.php
  66. 233
      application/index/controller/Order.php
  67. 187
      application/index/controller/Pay.php
  68. 73
      application/index/controller/Question.php
  69. 42
      application/index/controller/Single.php
  70. 34
      application/index/controller/Sms.php
  71. 127
      application/index/controller/Subaccount.php
  72. 104
      application/index/controller/Upload.php
  73. 212
      application/index/view/pay/index.html
  74. 439
      application/index/view/pay/index合同版本.html
  75. 14
      application/index/view/upload/index.html
  76. 64
      application/service/controller/Config.php
  77. 164
      application/service/controller/Fans.php
  78. 159
      application/service/controller/Index.php
  79. 155
      application/service/controller/api/Client.php
  80. 183
      application/service/controller/api/Push.php
  81. 69
      application/service/handler/PublishHandler.php
  82. 69
      application/service/handler/ReceiveHandler.php
  83. 161
      application/service/handler/WechatHandler.php
  84. 82
      application/service/queue/WechatQueue.php
  85. 53
      application/service/service/BuildService.php
  86. 151
      application/service/service/WechatService.php
  87. 109
      application/service/view/config/index.html
  88. 98
      application/service/view/fans/index.html
  89. 76
      application/service/view/fans/index_search.html
  90. 84
      application/service/view/index/index.html
  91. 77
      application/service/view/index/index_search.html
  92. 1
      application/service/view/not-auth.html
  93. 191
      application/store/command/AutoRun.php
  94. 61
      application/store/controller/Config.php
  95. 112
      application/store/controller/ExpressCompany.php
  96. 85
      application/store/controller/ExpressTemplate.php
  97. 197
      application/store/controller/Goods.php
  98. 97
      application/store/controller/GoodsCate.php
  99. 50
      application/store/controller/Member.php
  100. 61
      application/store/controller/Message.php

8
.idea/.gitignore

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

5
.idea/inspectionProfiles/profiles_settings.xml

@ -0,0 +1,5 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" />
</settings>
</component>

8
.idea/modules.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/xunxibaoapi.yaoyz.com.iml" filepath="$PROJECT_DIR$/.idea/xunxibaoapi.yaoyz.com.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
.idea/xunxibaoapi.yaoyz.com.iml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 邹景立
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

131
README.md

@ -0,0 +1,131 @@
[![Latest Stable Version](https://poser.pugx.org/zoujingli/thinkadmin/v/stable)](https://packagist.org/packages/zoujingli/thinkadmin) [![Total Downloads](https://poser.pugx.org/zoujingli/thinkadmin/downloads)](https://packagist.org/packages/zoujingli/thinkadmin) [![Latest Unstable Version](https://poser.pugx.org/zoujingli/thinkadmin/v/unstable)](https://packagist.org/packages/zoujingli/thinkadmin) [![License](https://poser.pugx.org/zoujingli/thinkadmin/license)](https://packagist.org/packages/zoujingli/thinkadmin)
## 大道至简 · 原生框架
ThinkAdmin V5 是一个基于 ThinkPHP 5.1 开发的后台管理系统。
我们致力于二次开发底层框架,提供完整的组件及API,基于此框架可以快速开发应用。
另外项目安装及二次开发可以参考 ThinkPHP 官方文档,数据库文件摆放在项目根目录下。
#### 注意事项
* 项目测试需要自行搭建环境导入数据库( admin_v5.sql )并修改配置( config/database.php );
* 若操作提示“测试系统禁止操作”等字样,需要删除演示路由配置( route/demo.php )或清空路由文件;
* 当前版本使用 ThinkPHP 5.1.x,对 PHP 版本标注不低于 PHP 5.6,具体请阅读 ThinkPHP 官方文档;
* 环境需开启 PATHINFO,不再支持 ThinkPHP 的 URL 兼容模式运行(源于如何优雅的展示);
## 技术支持
开发前请认真阅读 ThinkPHP 官方文档会对您有帮助哦!
本地开发命令`php think run`,使用`http://127.0.0.1:8000`访问项目。
PHP 开发技术交流( QQ 群 513350915)
[![PHP微信开发群 (SDK)](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=ae25cf789dafbef62e50a980ffc31242f150bc61a61164458216dd98c411832a)
## 注解权限
注解权限是指通过方法注释来实现后台RBAC授权管理,用注解来管理功能节点。
开发人员只需要写好注释,RBAC的节点会自动生成,只需要配置角色及用户就可以使用RBAC权限。
* 此版本的权限使用注解实现
* 注释必需使用标准的块注释,如下案例
* 其中`@auth true`表示访问需要权限验证
* 其中`@menu true`显示在菜单编辑的节点可选项
```php
/**
* 操作的名称
* @auth true # 表示需要验证权限
* @menu true # 在菜单编辑的节点可选项
*/
public function index(){
// @todo
}
```
## 代码仓库
ThinkAdmin 为 MIT 协议开源项目,安装使用或二次开发不受约束,欢迎 fork 项目。
部分代码来自互联网,若有异议可以联系作者进行删除。
* 在线体验地址:https://demo.thinkadmin.top (账号和密码都是 admin )
* Gitee仓库地址:https://gitee.com/zoujingli/ThinkAdmin
* GitHub仓库地址:https://github.com/zoujingli/ThinkAdmin
## 框架指令
* 执行 `build.cmd` 可更新 `Composer` 插件,会删除并替换 `vendor` 目录
* 执行 `php think run` 启用本地开发环境,访问 `http://127.0.0.1:8000`
#### 1. 线上代码更新
* 执行 `php think xsync:admin` 从线上服务更新 `admin` 模块的所有文件(注意文件安全)
* 执行 `php think xsync:wechat` 从线上服务更新 `wechat` 模块的所有文件(注意文件安全)
* 执行 `php think xsync:service` 从线上服务更新 `service` 模块的所有文件(注意文件安全)
* 执行 `php think xsync:plugs` 从线上服务更新 `plugs` 静态插件的部分文件(注意文件安全)
* 执行 `php think xsync:config` 从线上服务更新 `config` 项目配置的部分文件(注意文件安全)
#### 2. 微信资料管理
* 执行 `php think xfans:all` 更新已经对接的公众号全部列表
* 执行 `php think xfans:list` 更新已经对接的公众号粉丝列表
* 执行 `php think xfans:tags` 更新已经对接的公众号标签列表
* 执行 `php think xfans:black` 更新已经对接的公众号黑名单列表
#### 3. 守护进程管理
* 执行 `php think xtask:reset` 重启消息任务守护进程
* 执行 `php think xtask:start` 启动消息任务守护进程
* 执行 `php think xtask:state` 查询消息任务守护进程
* 执行 `php think xtask:stop` 暂停消息任务守护进程
#### 4. 其它自定工具
* 执行 `php think xclean:session` 清理无效的会话SESSION文件
* 执行 `php think xclean:store` 清理无效的订单信息及定时任务
## 特别感谢
|名称|版本|描述|链接|
|---|---|---|---|
|layui|2.4.5|UI组件库|https://github.com/sentsin/layui|
|ckeditor|4.10.1|富文件编辑器|https://github.com/ckeditor/ckeditor-dev|
|pluploader|3.1.2|文件上传工具|https://www.plupload.com|
|webuploader|0.1.5|暂时不使用了|https://github.com/fex-team/webuploader|
|font-awesome|4.7.0|字体图标库|https://github.com/FortAwesome/Font-Awesome|
|ThinkPHP|5.1.37|PHP基础框架|https://github.com/top-think/framework|
|ThinkLibrary|5.1.x-dev|ThinkPHP扩展组件|https://github.com/zoujingli/ThinkLibrary|
|WeChatDeveloper|1.2.9|微信公众号组件|https://github.com/zoujingli/WeChatDeveloper|
|WeOpenDeveloper|dev-master|微信开放平台组件|https://github.com/zoujingli/WeOpenDeveloper|
## 赞助打赏
![赞助](http://static.thinkadmin.top/pay.png)
## 项目版本
体验账号及密码都是`admin`
#### ThinkAdmin v1 基于 ThinkPHP 5.0 开发
* 在线体验地址:https://v1.thinkadmin.top
* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v1
* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v1
#### ThinkAdmin v2 基于 ThinkPHP 5.0 开发
* 在线体验地址:https://v2.thinkadmin.top
* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v2
* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v2
#### ThinkAdmin v3 基于 ThinkPHP 5.1 开发
* 在线体验地址:https://v3.thinkadmin.top
* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v3
* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v3
#### ThinkAdmin v4 基于 ThinkPHP 5.1 开发
* 在线体验地址:https://v4.thinkadmin.top
* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v4
* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v4
#### ThinkAdmin v5 基于 ThinkPHP 5.1 开发(后台权限基于注解实现)
* 在线体验地址:https://v5.thinkadmin.top
* Gitee 代码地址:https://gitee.com/zoujingli/ThinkAdmin/tree/v5
* Github 代码地址:https://github.com/zoujingli/ThinkAdmin/tree/v5

790
admin_v5.sql

@ -0,0 +1,790 @@
/*
Navicat Premium Data Transfer
Source Server : local.ctolog.com
Source Server Type : MySQL
Source Server Version : 50562
Source Host : 127.0.0.1:3306
Source Schema : admin_v4_1
Target Server Type : MySQL
Target Server Version : 50562
File Encoding : 65001
Date: 06/07/2019 19:07:04
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for store_express_company
-- ----------------------------
DROP TABLE IF EXISTS `store_express_company`;
CREATE TABLE `store_express_company` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`express_title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司名称',
`express_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司代码',
`express_desc` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '快递公司描述',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0.无效,1.有效)',
`sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态(1删除,0未删除)',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 95 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商城-快递-公司';
-- ----------------------------
-- Records of store_express_company
-- ----------------------------
INSERT INTO `store_express_company` VALUES (5, 'AAE全球专递', 'aae', NULL, 0, 0, 0, '2017-09-12 11:53:40');
INSERT INTO `store_express_company` VALUES (6, '安捷快递', 'anjie', '', 0, 0, 0, '2017-09-13 15:27:26');
INSERT INTO `store_express_company` VALUES (7, '安信达快递', 'anxindakuaixi', NULL, 0, 0, 0, '2017-09-13 16:05:19');
INSERT INTO `store_express_company` VALUES (8, '彪记快递', 'biaojikuaidi', NULL, 0, 0, 0, '2017-09-13 16:05:26');
INSERT INTO `store_express_company` VALUES (9, 'BHT', 'bht', '', 0, 0, 0, '2017-09-13 16:05:37');
INSERT INTO `store_express_company` VALUES (10, '百福东方国际物流', 'baifudongfang', NULL, 0, 0, 0, '2017-09-13 16:05:41');
INSERT INTO `store_express_company` VALUES (11, '中国东方(COE)', 'coe', NULL, 0, 0, 0, '2017-09-13 16:05:48');
INSERT INTO `store_express_company` VALUES (12, '长宇物流', 'changyuwuliu', NULL, 0, 0, 0, '2017-09-13 16:05:58');
INSERT INTO `store_express_company` VALUES (13, '大田物流', 'datianwuliu', NULL, 0, 0, 0, '2017-09-13 16:06:06');
INSERT INTO `store_express_company` VALUES (14, '德邦物流', 'debangwuliu', '', 0, 1, 0, '2017-09-13 16:06:14');
INSERT INTO `store_express_company` VALUES (15, 'DHL', 'dhl', NULL, 0, 0, 0, '2017-09-13 16:06:24');
INSERT INTO `store_express_company` VALUES (16, 'DPEX', 'dpex', NULL, 0, 0, 0, '2017-09-13 16:06:29');
INSERT INTO `store_express_company` VALUES (17, 'd速快递', 'dsukuaidi', NULL, 0, 0, 0, '2017-09-13 16:06:34');
INSERT INTO `store_express_company` VALUES (18, '递四方', 'disifang', NULL, 0, 0, 0, '2017-09-13 16:06:40');
INSERT INTO `store_express_company` VALUES (19, 'EMS快递', 'ems', '', 1, 0, 0, '2017-09-13 16:06:47');
INSERT INTO `store_express_company` VALUES (20, 'FEDEX(国外)', 'fedex', NULL, 0, 0, 0, '2017-09-13 16:06:56');
INSERT INTO `store_express_company` VALUES (21, '飞康达物流', 'feikangda', NULL, 0, 0, 0, '2017-09-13 16:07:03');
INSERT INTO `store_express_company` VALUES (22, '凤凰快递', 'fenghuangkuaidi', NULL, 0, 0, 0, '2017-09-13 16:07:10');
INSERT INTO `store_express_company` VALUES (23, '飞快达', 'feikuaida', NULL, 0, 0, 0, '2017-09-13 16:07:16');
INSERT INTO `store_express_company` VALUES (24, '国通快递', 'guotongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:07:27');
INSERT INTO `store_express_company` VALUES (25, '港中能达物流', 'ganzhongnengda', NULL, 0, 0, 0, '2017-09-13 16:07:33');
INSERT INTO `store_express_company` VALUES (26, '广东邮政物流', 'guangdongyouzhengwuliu', NULL, 0, 0, 0, '2017-09-13 16:08:22');
INSERT INTO `store_express_company` VALUES (27, '共速达', 'gongsuda', NULL, 0, 0, 0, '2017-09-13 16:08:48');
INSERT INTO `store_express_company` VALUES (28, '汇通快运', 'huitongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:08:56');
INSERT INTO `store_express_company` VALUES (29, '恒路物流', 'hengluwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:02');
INSERT INTO `store_express_company` VALUES (30, '华夏龙物流', 'huaxialongwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:12');
INSERT INTO `store_express_company` VALUES (31, '海红', 'haihongwangsong', NULL, 0, 0, 0, '2017-09-13 16:09:20');
INSERT INTO `store_express_company` VALUES (32, '海外环球', 'haiwaihuanqiu', NULL, 0, 0, 0, '2017-09-13 16:09:27');
INSERT INTO `store_express_company` VALUES (33, '佳怡物流', 'jiayiwuliu', NULL, 0, 0, 0, '2017-09-13 16:09:35');
INSERT INTO `store_express_company` VALUES (34, '京广速递', 'jinguangsudikuaijian', NULL, 0, 0, 0, '2017-09-13 16:09:42');
INSERT INTO `store_express_company` VALUES (35, '急先达', 'jixianda', NULL, 0, 0, 0, '2017-09-13 16:09:49');
INSERT INTO `store_express_company` VALUES (36, '佳吉物流', 'jjwl', NULL, 0, 0, 0, '2017-09-13 16:10:01');
INSERT INTO `store_express_company` VALUES (37, '加运美物流', 'jymwl', NULL, 0, 0, 0, '2017-09-13 16:10:13');
INSERT INTO `store_express_company` VALUES (38, '金大物流', 'jindawuliu', NULL, 0, 0, 0, '2017-09-13 16:10:22');
INSERT INTO `store_express_company` VALUES (39, '嘉里大通', 'jialidatong', NULL, 0, 0, 0, '2017-09-13 16:10:33');
INSERT INTO `store_express_company` VALUES (40, '晋越快递', 'jykd', NULL, 0, 0, 0, '2017-09-13 16:10:40');
INSERT INTO `store_express_company` VALUES (41, '快捷速递', 'kuaijiesudi', NULL, 0, 0, 0, '2017-09-13 16:10:49');
INSERT INTO `store_express_company` VALUES (42, '联邦快递(国内)', 'lianb', NULL, 0, 0, 0, '2017-09-13 16:10:58');
INSERT INTO `store_express_company` VALUES (43, '联昊通物流', 'lianhaowuliu', NULL, 0, 0, 0, '2017-09-13 16:11:07');
INSERT INTO `store_express_company` VALUES (44, '龙邦物流', 'longbanwuliu', NULL, 0, 0, 0, '2017-09-13 16:11:15');
INSERT INTO `store_express_company` VALUES (45, '立即送', 'lijisong', NULL, 0, 0, 0, '2017-09-13 16:11:25');
INSERT INTO `store_express_company` VALUES (46, '乐捷递', 'lejiedi', NULL, 0, 0, 0, '2017-09-13 16:11:36');
INSERT INTO `store_express_company` VALUES (47, '民航快递', 'minghangkuaidi', NULL, 0, 0, 0, '2017-09-13 16:11:45');
INSERT INTO `store_express_company` VALUES (48, '美国快递', 'meiguokuaidi', NULL, 0, 0, 0, '2017-09-13 16:11:53');
INSERT INTO `store_express_company` VALUES (49, '门对门', 'menduimen', NULL, 0, 0, 0, '2017-09-13 16:12:01');
INSERT INTO `store_express_company` VALUES (50, 'OCS', 'ocs', NULL, 0, 0, 0, '2017-09-13 16:12:10');
INSERT INTO `store_express_company` VALUES (51, '配思货运', 'peisihuoyunkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:18');
INSERT INTO `store_express_company` VALUES (52, '全晨快递', 'quanchenkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:26');
INSERT INTO `store_express_company` VALUES (53, '全峰快递', 'quanfengkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:34');
INSERT INTO `store_express_company` VALUES (54, '全际通物流', 'quanjitong', NULL, 0, 0, 0, '2017-09-13 16:12:41');
INSERT INTO `store_express_company` VALUES (55, '全日通快递', 'quanritongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:49');
INSERT INTO `store_express_company` VALUES (56, '全一快递', 'quanyikuaidi', NULL, 0, 0, 0, '2017-09-13 16:12:56');
INSERT INTO `store_express_company` VALUES (57, '如风达', 'rufengda', NULL, 0, 0, 0, '2017-09-13 16:13:03');
INSERT INTO `store_express_company` VALUES (58, '三态速递', 'santaisudi', NULL, 0, 0, 0, '2017-09-13 16:13:15');
INSERT INTO `store_express_company` VALUES (59, '盛辉物流', 'shenghuiwuliu', NULL, 0, 0, 0, '2017-09-13 16:13:22');
INSERT INTO `store_express_company` VALUES (60, '申通', 'shentong', NULL, 0, 0, 0, '2017-09-13 16:13:34');
INSERT INTO `store_express_company` VALUES (61, '顺丰', 'shunfeng', '', 0, 0, 0, '2017-09-13 16:13:41');
INSERT INTO `store_express_company` VALUES (62, '速尔物流', 'sue', NULL, 0, 0, 0, '2017-09-13 16:13:48');
INSERT INTO `store_express_company` VALUES (63, '盛丰物流', 'shengfeng', NULL, 0, 0, 0, '2017-09-13 16:13:55');
INSERT INTO `store_express_company` VALUES (64, '赛澳递', 'saiaodi', NULL, 0, 0, 0, '2017-09-13 16:14:02');
INSERT INTO `store_express_company` VALUES (65, '天地华宇', 'tiandihuayu', NULL, 0, 0, 0, '2017-09-13 16:14:11');
INSERT INTO `store_express_company` VALUES (66, '天天快递', 'tiantian', NULL, 0, 0, 0, '2017-09-13 16:14:19');
INSERT INTO `store_express_company` VALUES (67, 'TNT', 'tnt', NULL, 0, 0, 0, '2017-09-13 16:14:26');
INSERT INTO `store_express_company` VALUES (68, 'UPS', 'ups', NULL, 0, 0, 0, '2017-09-13 16:14:29');
INSERT INTO `store_express_company` VALUES (69, '万家物流', 'wanjiawuliu', NULL, 0, 0, 0, '2017-09-13 16:14:37');
INSERT INTO `store_express_company` VALUES (70, '文捷航空速递', 'wenjiesudi', NULL, 0, 0, 0, '2017-09-13 16:14:46');
INSERT INTO `store_express_company` VALUES (71, '伍圆', 'wuyuan', NULL, 0, 0, 0, '2017-09-13 16:14:52');
INSERT INTO `store_express_company` VALUES (72, '万象物流', 'wxwl', NULL, 0, 0, 0, '2017-09-13 16:15:00');
INSERT INTO `store_express_company` VALUES (73, '新邦物流', 'xinbangwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:06');
INSERT INTO `store_express_company` VALUES (74, '信丰物流', 'xinfengwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:15');
INSERT INTO `store_express_company` VALUES (75, '亚风速递', 'yafengsudi', NULL, 0, 0, 0, '2017-09-13 16:15:23');
INSERT INTO `store_express_company` VALUES (76, '一邦速递', 'yibangwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:30');
INSERT INTO `store_express_company` VALUES (77, '优速物流', 'youshuwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:36');
INSERT INTO `store_express_company` VALUES (78, '邮政包裹挂号信', 'youzhengguonei', NULL, 0, 3, 0, '2017-09-13 16:15:44');
INSERT INTO `store_express_company` VALUES (79, '邮政国际包裹挂号信', 'youzhengguoji', NULL, 0, 2, 0, '2017-09-13 16:15:51');
INSERT INTO `store_express_company` VALUES (80, '远成物流', 'yuanchengwuliu', NULL, 0, 0, 0, '2017-09-13 16:15:57');
INSERT INTO `store_express_company` VALUES (81, '圆通速递', 'yuantong', '', 1, 1, 0, '2017-09-13 16:16:03');
INSERT INTO `store_express_company` VALUES (82, '源伟丰快递', 'yuanweifeng', NULL, 0, 0, 0, '2017-09-13 16:16:10');
INSERT INTO `store_express_company` VALUES (83, '元智捷诚快递', 'yuanzhijiecheng', NULL, 0, 0, 0, '2017-09-13 16:16:17');
INSERT INTO `store_express_company` VALUES (84, '韵达快运', 'yunda', NULL, 0, 0, 0, '2017-09-13 16:16:24');
INSERT INTO `store_express_company` VALUES (85, '运通快递', 'yuntongkuaidi', NULL, 0, 0, 0, '2017-09-13 16:16:33');
INSERT INTO `store_express_company` VALUES (86, '越丰物流', 'yuefengwuliu', NULL, 0, 0, 0, '2017-09-13 16:16:40');
INSERT INTO `store_express_company` VALUES (87, '源安达', 'yad', NULL, 0, 0, 0, '2017-09-13 16:16:47');
INSERT INTO `store_express_company` VALUES (88, '银捷速递', 'yinjiesudi', NULL, 0, 0, 0, '2017-09-13 16:16:56');
INSERT INTO `store_express_company` VALUES (89, '宅急送', 'zhaijisong', NULL, 0, 0, 0, '2017-09-13 16:17:03');
INSERT INTO `store_express_company` VALUES (90, '中铁快运', 'zhongtiekuaiyun', NULL, 0, 0, 0, '2017-09-13 16:17:10');
INSERT INTO `store_express_company` VALUES (91, '中通速递', 'zhongtong', '', 0, 0, 0, '2017-09-13 16:17:16');
INSERT INTO `store_express_company` VALUES (92, '中邮物流', 'zhongyouwuliu', NULL, 0, 0, 0, '2017-09-13 16:17:27');
INSERT INTO `store_express_company` VALUES (93, '忠信达', 'zhongxinda', NULL, 0, 0, 0, '2017-09-13 16:17:34');
INSERT INTO `store_express_company` VALUES (94, '芝麻开门', 'zhimakaimen', '', 1, 0, 0, '2017-09-13 16:17:41');
-- ----------------------------
-- Table structure for store_express_template
-- ----------------------------
DROP TABLE IF EXISTS `store_express_template`;
CREATE TABLE `store_express_template` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`rule` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '省份规则内容',
`order_reduction_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '订单满减状态',
`order_reduction_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '订单满减金额',
`first_number` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '首件数量',
`first_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '首件邮费',
`next_number` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '续件数量',
`next_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '续件邮费',
`is_default` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '默认规则',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_express_template_is_default`(`is_default`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商城-快递-模板';
-- ----------------------------
-- Table structure for store_goods
-- ----------------------------
DROP TABLE IF EXISTS `store_goods`;
CREATE TABLE `store_goods` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`cate_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品分类',
`title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品标题',
`logo` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品图标',
`specs` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品规格JSON',
`lists` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品列表JSON',
`image` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品图片',
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '商品内容',
`number_sales` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '销售数量',
`number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '库库数量',
`price_rate` decimal(20, 4) UNSIGNED NULL DEFAULT 0.0000 COMMENT '返利比例',
`price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '统一运费',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '销售状态',
`sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_goods_status`(`status`) USING BTREE,
INDEX `index_store_goods_cate_id`(`cate_id`) USING BTREE,
INDEX `index_store_goods_is_deleted`(`is_deleted`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品-记录';
-- ----------------------------
-- Table structure for store_goods_cate
-- ----------------------------
DROP TABLE IF EXISTS `store_goods_cate`;
CREATE TABLE `store_goods_cate` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`logo` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '分类图标',
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '分类名称',
`desc` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '分类描述',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '销售状态',
`sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_goods_cate_is_deleted`(`is_deleted`) USING BTREE,
INDEX `index_store_goods_cate_status`(`status`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品-分类';
-- ----------------------------
-- Table structure for store_goods_list
-- ----------------------------
DROP TABLE IF EXISTS `store_goods_list`;
CREATE TABLE `store_goods_list` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`sku` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'sku',
`goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品ID',
`goods_spec` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '商品规格',
`price_market` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品标价',
`price_selling` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品售价',
`number_sales` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '销售数量',
`number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品库存',
`number_virtual` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '虚拟销量',
`number_express` bigint(20) UNSIGNED NULL DEFAULT 1 COMMENT '快递数量',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '商品状态',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_goods_list_id`(`goods_id`) USING BTREE,
INDEX `index_store_goods_list_spec`(`goods_spec`) USING BTREE,
INDEX `index_store_goods_list_status`(`status`) USING BTREE,
INDEX `index_store_goods_list_sku`(`sku`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品-详情';
-- ----------------------------
-- Table structure for store_goods_stock
-- ----------------------------
DROP TABLE IF EXISTS `store_goods_stock`;
CREATE TABLE `store_goods_stock` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品ID',
`goods_spec` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '商品规格',
`number_stock` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品库存',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_goods_stock_gid`(`goods_id`) USING BTREE,
INDEX `index_store_goods_stock_spec`(`goods_spec`(191)) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '商品-入库';
-- ----------------------------
-- Table structure for store_member
-- ----------------------------
DROP TABLE IF EXISTS `store_member`;
CREATE TABLE `store_member` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`openid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '微信OPENID',
`headimg` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '头像地址',
`nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '微信昵称',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系手机',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '真实姓名',
`vip_level` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '会员级别(0游客,1为临时,2为VIP1,3为VIP2)',
`vip_date` date NULL DEFAULT NULL COMMENT '保级日期',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_member_openid`(`openid`) USING BTREE,
INDEX `index_store_member_phone`(`phone`) USING BTREE,
INDEX `index_store_member_vip_level`(`vip_level`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员-记录';
-- ----------------------------
-- Table structure for store_member_address
-- ----------------------------
DROP TABLE IF EXISTS `store_member_address`;
CREATE TABLE `store_member_address` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货姓名',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货手机',
`province` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址-省份',
`city` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址-城市',
`area` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址-区域',
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址-详情',
`is_default` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '默认地址',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_member_address_mid`(`mid`) USING BTREE,
INDEX `index_store_member_address_is_default`(`is_default`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员-地址';
-- ----------------------------
-- Table structure for store_member_sms_history
-- ----------------------------
DROP TABLE IF EXISTS `store_member_sms_history`;
CREATE TABLE `store_member_sms_history` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '目标手机',
`content` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '短信内容',
`result` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '返回结果',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_member_sms_history_phone`(`phone`) USING BTREE,
INDEX `index_store_member_sms_history_mid`(`mid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员-短信';
-- ----------------------------
-- Table structure for store_order
-- ----------------------------
DROP TABLE IF EXISTS `store_order`;
CREATE TABLE `store_order` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
`order_no` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单单号',
`from_mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '推荐会员ID',
`price_total` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '待付金额统计',
`price_goods` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '商品费用统计',
`price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '快递费用统计',
`price_rate_amount` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '返利金额统计',
`pay_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '支付状态(0未支付,1已支付)',
`pay_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '支付方式',
`pay_price` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '支付金额',
`pay_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '支付单号',
`pay_at` datetime NULL DEFAULT NULL COMMENT '支付时间',
`cancel_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '取消状态',
`cancel_at` datetime NULL DEFAULT NULL COMMENT '取消时间',
`cancel_desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '取消描述',
`refund_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '退款状态(0未退款,1待退款,2已退款)',
`refund_at` datetime NULL DEFAULT NULL COMMENT '退款时间',
`refund_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '退款单号',
`refund_price` decimal(20, 2) NULL DEFAULT 0.00 COMMENT '退款金额',
`refund_desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '退款描述',
`express_state` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '发货状态(0未发货,1已发货,2已签收)',
`express_company_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发货快递公司编码',
`express_company_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发货快递公司名称',
`express_send_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发货单号',
`express_send_at` datetime NULL DEFAULT NULL COMMENT '发货时间',
`express_address_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '收货地址ID',
`express_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货人姓名',
`express_phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货人手机',
`express_province` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货地址省份',
`express_city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货地址城市',
`express_area` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货地址区域',
`express_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '收货详细地址',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '订单状态(0已取消,1预订单待补全,2新订单待支付,3已支付待发货,4已发货待签收,5已完成)',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_groups_order_mid`(`mid`) USING BTREE,
INDEX `index_store_groups_order_order_no`(`order_no`) USING BTREE,
INDEX `index_store_groups_order_pay_state`(`pay_state`) USING BTREE,
INDEX `index_store_groups_order_cancel_state`(`cancel_state`) USING BTREE,
INDEX `index_store_groups_order_refund_state`(`refund_state`) USING BTREE,
INDEX `index_store_groups_order_status`(`status`) USING BTREE,
INDEX `index_store_groups_order_pay_no`(`pay_no`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单-记录';
-- ----------------------------
-- Table structure for store_order_list
-- ----------------------------
DROP TABLE IF EXISTS `store_order_list`;
CREATE TABLE `store_order_list` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`mid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '会员ID',
`from_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '推荐会员',
`order_no` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '订单单号',
`goods_id` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品标识',
`goods_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '商品标题',
`goods_logo` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '商品图标',
`goods_spec` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '商品规格',
`price_real` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '交易金额',
`price_selling` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '销售价格',
`price_market` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '市场价格',
`price_express` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '快递费用',
`price_rate` decimal(20, 4) UNSIGNED NULL DEFAULT 0.0000 COMMENT '分成比例',
`price_rate_amount` decimal(20, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '分成金额',
`number_goods` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '商品数量',
`number_express` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '快递数量',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_store_goods_list_id`(`goods_id`) USING BTREE,
INDEX `index_store_goods_list_spec`(`goods_spec`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单-详情';
-- ----------------------------
-- Table structure for system_auth
-- ----------------------------
DROP TABLE IF EXISTS `system_auth`;
CREATE TABLE `system_auth` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限名称',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '权限状态',
`sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序权重',
`desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注说明',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_auth_status`(`status`) USING BTREE,
INDEX `index_system_auth_title`(`title`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-权限';
-- ----------------------------
-- Table structure for system_auth_node
-- ----------------------------
DROP TABLE IF EXISTS `system_auth_node`;
CREATE TABLE `system_auth_node` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`auth` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '角色',
`node` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '节点',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_auth_auth`(`auth`) USING BTREE,
INDEX `index_system_auth_node`(`node`(191)) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-权限-授权';
-- ----------------------------
-- Table structure for system_config
-- ----------------------------
DROP TABLE IF EXISTS `system_config`;
CREATE TABLE `system_config` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '配置名',
`value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '配置值',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_config_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 74 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-配置';
-- ----------------------------
-- Records of system_config
-- ----------------------------
INSERT INTO `system_config` VALUES (1, 'app_name', 'ThinkAdmin');
INSERT INTO `system_config` VALUES (2, 'site_name', 'ThinkAdmin');
INSERT INTO `system_config` VALUES (3, 'app_version', 'v5');
INSERT INTO `system_config` VALUES (4, 'site_copy', '©版权所有 2014-2018 楚才科技');
INSERT INTO `system_config` VALUES (5, 'site_icon', '/upload/decb0fe26fa3f486/b3f6521bf29403c8.png');
INSERT INTO `system_config` VALUES (7, 'miitbeian', '粤ICP备16006642号-2');
INSERT INTO `system_config` VALUES (8, 'storage_type', 'local');
INSERT INTO `system_config` VALUES (9, 'storage_local_exts', 'doc,gif,icon,jpg,mp3,mp4,p12,pem,png,rar');
INSERT INTO `system_config` VALUES (10, 'storage_qiniu_bucket', 'https');
INSERT INTO `system_config` VALUES (11, 'storage_qiniu_domain', '用你自己的吧');
INSERT INTO `system_config` VALUES (12, 'storage_qiniu_access_key', '用你自己的吧');
INSERT INTO `system_config` VALUES (13, 'storage_qiniu_secret_key', '用你自己的吧');
INSERT INTO `system_config` VALUES (14, 'storage_oss_bucket', 'cuci-mytest');
INSERT INTO `system_config` VALUES (15, 'storage_oss_endpoint', 'oss-cn-hangzhou.aliyuncs.com');
INSERT INTO `system_config` VALUES (16, 'storage_oss_domain', '用你自己的吧');
INSERT INTO `system_config` VALUES (17, 'storage_oss_keyid', '用你自己的吧');
INSERT INTO `system_config` VALUES (18, 'storage_oss_secret', '用你自己的吧');
INSERT INTO `system_config` VALUES (36, 'storage_oss_is_https', 'http');
INSERT INTO `system_config` VALUES (43, 'storage_qiniu_region', '华东');
INSERT INTO `system_config` VALUES (44, 'storage_qiniu_is_https', 'https');
INSERT INTO `system_config` VALUES (45, 'wechat_mch_id', '1332187001');
INSERT INTO `system_config` VALUES (46, 'wechat_mch_key', 'A82DC5BD1F3359081049C568D8502BC5');
INSERT INTO `system_config` VALUES (47, 'wechat_mch_ssl_type', 'p12');
INSERT INTO `system_config` VALUES (48, 'wechat_mch_ssl_p12', '65b8e4f56718182d/1bc857ee646aa15d.p12');
INSERT INTO `system_config` VALUES (49, 'wechat_mch_ssl_key', 'cc2e3e1345123930/c407d033294f283d.pem');
INSERT INTO `system_config` VALUES (50, 'wechat_mch_ssl_cer', '966eaf89299e9c95/7014872cc109b29a.pem');
INSERT INTO `system_config` VALUES (51, 'wechat_token', 'mytoken');
INSERT INTO `system_config` VALUES (52, 'wechat_appid', 'wx60a43dd8161666d4');
INSERT INTO `system_config` VALUES (53, 'wechat_appsecret', '9978422e0e431643d4b42868d183d60b');
INSERT INTO `system_config` VALUES (54, 'wechat_encodingaeskey', '');
INSERT INTO `system_config` VALUES (55, 'wechat_push_url', '消息推送地址:http://127.0.0.1:8000/wechat/api.push');
INSERT INTO `system_config` VALUES (56, 'wechat_type', 'thr');
INSERT INTO `system_config` VALUES (57, 'wechat_thr_appid', 'wx60a43dd8161666d4');
INSERT INTO `system_config` VALUES (58, 'wechat_thr_appkey', 'd2c0139213d7a27898ca047d81a617be');
INSERT INTO `system_config` VALUES (60, 'wechat_thr_appurl', '消息推送地址:http://127.0.0.1:8000/wechat/api.push');
INSERT INTO `system_config` VALUES (61, 'component_appid', 'wx28b58798480874f9');
INSERT INTO `system_config` VALUES (62, 'component_appsecret', '87ddce1cc24e4cd691039f926febd942');
INSERT INTO `system_config` VALUES (63, 'component_token', 'P8QHTIxpBEq88IrxatqhgpBm2OAQROkI');
INSERT INTO `system_config` VALUES (64, 'component_encodingaeskey', 'L5uFIa0U6KLalPyXckyqoVIJYLhsfrg8k9YzybZIHsx');
INSERT INTO `system_config` VALUES (65, 'system_message_state', '0');
INSERT INTO `system_config` VALUES (66, 'sms_zt_username', '可以找CUCI申请');
INSERT INTO `system_config` VALUES (67, 'sms_zt_password', '可以找CUCI申请');
INSERT INTO `system_config` VALUES (68, 'sms_reg_template', '您的验证码为{code},请在十分钟内完成操作!');
INSERT INTO `system_config` VALUES (69, 'sms_secure', '可以找CUCI申请');
INSERT INTO `system_config` VALUES (70, 'store_title', '测试商城');
INSERT INTO `system_config` VALUES (71, 'store_order_wait_time', '0.50');
INSERT INTO `system_config` VALUES (72, 'store_order_clear_time', '24.00');
INSERT INTO `system_config` VALUES (73, 'store_order_confirm_time', '60.00');
-- ----------------------------
-- Table structure for system_data
-- ----------------------------
DROP TABLE IF EXISTS `system_data`;
CREATE TABLE `system_data` (
`id` bigint(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '配置名',
`value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '配置值',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_data_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-数据';
-- ----------------------------
-- Table structure for system_jobs
-- ----------------------------
DROP TABLE IF EXISTS `system_jobs`;
CREATE TABLE `system_jobs` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`queue` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`attempts` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
`reserved` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
`reserved_at` int(10) UNSIGNED NULL DEFAULT NULL,
`available_at` int(10) UNSIGNED NOT NULL,
`created_at` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_jobs_reserved`(`reserved`) USING BTREE,
INDEX `index_system_jobs_attempts`(`attempts`) USING BTREE,
INDEX `index_system_jobs_reserved_at`(`reserved_at`) USING BTREE,
INDEX `index_system_jobs_available_at`(`available_at`) USING BTREE,
INDEX `index_system_jobs_create_at`(`created_at`) USING BTREE,
INDEX `index_system_jobs_queue`(`queue`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-任务';
-- ----------------------------
-- Table structure for system_jobs_log
-- ----------------------------
DROP TABLE IF EXISTS `system_jobs_log`;
CREATE TABLE `system_jobs_log` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '任务名称',
`uri` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '任务对象',
`later` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '任务延时',
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '任务数据',
`desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '任务描述',
`double` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '任务多开',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '任务状态(1新任务,2任务进行中,3任务成功,4任务失败)',
`status_at` datetime NULL DEFAULT NULL COMMENT '任务状态时间',
`status_desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '任务状态描述',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_jobs_log_status`(`status`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-任务-日志';
-- ----------------------------
-- Table structure for system_log
-- ----------------------------
DROP TABLE IF EXISTS `system_log`;
CREATE TABLE `system_log` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`node` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '当前操作节点',
`geoip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作者IP地址',
`action` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作行为名称',
`content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作内容描述',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '操作人用户名',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-日志';
-- ----------------------------
-- Table structure for system_menu
-- ----------------------------
DROP TABLE IF EXISTS `system_menu`;
CREATE TABLE `system_menu` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`pid` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '父ID',
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '名称',
`node` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '节点代码',
`icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '菜单图标',
`url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '链接',
`params` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '链接参数',
`target` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '_self' COMMENT '打开方式',
`sort` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '菜单排序',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0:禁用,1:启用)',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_system_menu_node`(`node`(191)) USING BTREE,
INDEX `index_system_menu_status`(`status`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 56 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-菜单';
-- ----------------------------
-- Records of system_menu
-- ----------------------------
INSERT INTO `system_menu` VALUES (1, 0, '后台首页', '', '', 'admin/index/main', '', '_self', 500, 1, '2018-09-05 17:59:38');
INSERT INTO `system_menu` VALUES (2, 0, '系统管理', '', '', '#', '', '_self', 100, 1, '2018-09-05 18:04:52');
INSERT INTO `system_menu` VALUES (3, 4, '系统菜单管理', '', 'layui-icon layui-icon-layouts', 'admin/menu/index', '', '_self', 1, 1, '2018-09-05 18:05:26');
INSERT INTO `system_menu` VALUES (4, 2, '系统配置', '', '', '#', '', '_self', 20, 1, '2018-09-05 18:07:17');
INSERT INTO `system_menu` VALUES (5, 12, '系统用户管理', '', 'layui-icon layui-icon-username', 'admin/user/index', '', '_self', 1, 1, '2018-09-06 11:10:42');
INSERT INTO `system_menu` VALUES (7, 12, '访问权限管理', '', 'layui-icon layui-icon-vercode', 'admin/auth/index', '', '_self', 2, 1, '2018-09-06 15:17:14');
INSERT INTO `system_menu` VALUES (11, 4, '系统参数配置', '', 'layui-icon layui-icon-set', 'admin/config/info', '', '_self', 4, 1, '2018-09-06 16:43:47');
INSERT INTO `system_menu` VALUES (12, 2, '权限管理', '', '', '#', '', '_self', 10, 1, '2018-09-06 18:01:31');
INSERT INTO `system_menu` VALUES (13, 0, '商城管理', '', '', '#', '', '_self', 400, 1, '2018-10-12 13:56:29');
INSERT INTO `system_menu` VALUES (14, 48, '商品信息管理', '', 'layui-icon layui-icon-component', 'store/goods/index', '', '_self', 3, 1, '2018-10-12 13:56:48');
INSERT INTO `system_menu` VALUES (16, 0, '微信管理', '', '', '#', '', '_self', 300, 1, '2018-10-31 15:15:27');
INSERT INTO `system_menu` VALUES (17, 16, '微信管理', '', '', '#', '', '_self', 20, 1, '2018-10-31 15:16:46');
INSERT INTO `system_menu` VALUES (18, 17, '微信授权配置', '', 'layui-icon layui-icon-set', 'wechat/config/options', '', '_self', 2, 1, '2018-10-31 15:17:11');
INSERT INTO `system_menu` VALUES (19, 17, '微信支付配置', '', 'layui-icon layui-icon-rmb', 'wechat/config/payment', '', '_self', 1, 1, '2018-10-31 18:28:09');
INSERT INTO `system_menu` VALUES (20, 16, '微信定制', '', '', '#', '', '_self', 10, 1, '2018-11-13 11:46:27');
INSERT INTO `system_menu` VALUES (21, 20, '图文素材管理', '', 'layui-icon layui-icon-template', 'wechat/news/index', '', '_self', 6, 1, '2018-11-13 11:46:55');
INSERT INTO `system_menu` VALUES (22, 20, '粉丝信息管理', '', 'layui-icon layui-icon-user', 'wechat/fans/index', '', '_self', 5, 1, '2018-11-15 09:51:13');
INSERT INTO `system_menu` VALUES (23, 20, '回复规则管理', '', 'layui-icon layui-icon-engine', 'wechat/keys/index', '', '_self', 4, 1, '2018-11-22 11:29:08');
INSERT INTO `system_menu` VALUES (24, 20, '关注回复配置', '', 'layui-icon layui-icon-senior', 'wechat/keys/subscribe', '', '_self', 3, 1, '2018-11-27 11:45:28');
INSERT INTO `system_menu` VALUES (25, 20, '默认回复配置', '', 'layui-icon layui-icon-survey', 'wechat/keys/defaults', '', '_self', 2, 1, '2018-11-27 11:45:58');
INSERT INTO `system_menu` VALUES (26, 20, '微信菜单管理', '', 'layui-icon layui-icon-cellphone', 'wechat/menu/index', '', '_self', 1, 1, '2018-11-27 17:56:56');
INSERT INTO `system_menu` VALUES (27, 4, '系统任务管理', '', 'layui-icon layui-icon-log', 'admin/queue/index', '', '_self', 3, 1, '2018-11-29 11:13:34');
INSERT INTO `system_menu` VALUES (37, 0, '开放平台', '', '', '#', '', '_self', 200, 1, '2018-12-28 13:29:25');
INSERT INTO `system_menu` VALUES (38, 40, '开放平台配置', '', 'layui-icon layui-icon-set', 'service/config/index', '', '_self', 0, 1, '2018-12-28 13:29:44');
INSERT INTO `system_menu` VALUES (39, 40, '公众授权管理', '', 'layui-icon layui-icon-template-1', 'service/index/index', '', '_self', 0, 1, '2018-12-28 13:30:07');
INSERT INTO `system_menu` VALUES (40, 37, '平台管理', '', '', '#', '', '_self', 0, 1, '2018-12-28 16:05:46');
INSERT INTO `system_menu` VALUES (42, 48, '会员信息管理', '', 'layui-icon layui-icon-user', 'store/member/index', '', '_self', 1, 1, '2019-01-22 14:24:23');
INSERT INTO `system_menu` VALUES (43, 48, '订单记录管理', '', 'layui-icon layui-icon-template-1', 'store/order/index', '', '_self', 2, 1, '2019-01-22 14:46:22');
INSERT INTO `system_menu` VALUES (44, 48, '商品分类管理', '', 'layui-icon layui-icon-app', 'store/goods_cate/index', '', '_self', 4, 1, '2019-01-23 10:41:06');
INSERT INTO `system_menu` VALUES (45, 47, '商城参数配置', '', 'layui-icon layui-icon-set', 'store/config/index', '', '_self', 5, 1, '2019-01-24 16:47:33');
INSERT INTO `system_menu` VALUES (46, 47, '短信发送记录', '', 'layui-icon layui-icon-console', 'store/message/index', '', '_self', 4, 1, '2019-01-24 18:09:58');
INSERT INTO `system_menu` VALUES (47, 13, '商城配置', '', '', '#', '', '_self', 20, 1, '2019-01-25 16:47:49');
INSERT INTO `system_menu` VALUES (48, 13, '数据管理', '', '', '#', '', '_self', 10, 1, '2019-01-25 16:48:35');
INSERT INTO `system_menu` VALUES (49, 4, '系统日志管理', '', 'layui-icon layui-icon-form', 'admin/oplog/index', '', '_self', 2, 1, '2019-02-18 12:56:56');
INSERT INTO `system_menu` VALUES (50, 47, '快递公司管理', '', 'layui-icon layui-icon-form', 'store/express_company/index', '', '_self', 3, 1, '2019-04-01 17:10:59');
INSERT INTO `system_menu` VALUES (52, 47, '邮费模板管理', '', 'layui-icon layui-icon-fonts-clear', 'store/express_template/index', '', '_self', 1, 1, '2019-04-23 13:17:10');
INSERT INTO `system_menu` VALUES (55, 17, '微信数据统计', '', 'layui-icon layui-icon-chart-screen', 'wechat/index/index', '', '_self', 3, 1, '2019-06-15 15:03:51');
-- ----------------------------
-- Table structure for system_user
-- ----------------------------
DROP TABLE IF EXISTS `system_user`;
CREATE TABLE `system_user` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户账号',
`password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户密码',
`qq` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系QQ',
`mail` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系邮箱',
`phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系手机',
`login_at` datetime NULL DEFAULT NULL COMMENT '登录时间',
`login_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '登录IP',
`login_num` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '登录次数',
`authorize` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '权限授权',
`desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注说明',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0:禁用,1:启用)',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除(1:删除,0:未删)',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `index_system_user_username`(`username`) USING BTREE,
INDEX `index_system_user_status`(`status`) USING BTREE,
INDEX `index_system_user_deleted`(`is_deleted`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10001 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-用户';
-- ----------------------------
-- Records of system_user
-- ----------------------------
INSERT INTO `system_user` VALUES (10000, 'admin', '21232f297a57a5a743894a0e4a801fc3', '22222222', '', '', '2019-07-06 18:29:31', '127.0.0.1', 611, '', '', 1, 0, '2015-11-13 15:14:22');
-- ----------------------------
-- Table structure for wechat_fans
-- ----------------------------
DROP TABLE IF EXISTS `wechat_fans`;
CREATE TABLE `wechat_fans` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`appid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
`unionid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '粉丝unionid',
`openid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '粉丝openid',
`tagid_list` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '粉丝标签id',
`is_black` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '是否为黑名单状态',
`subscribe` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '关注状态(0未关注,1已关注)',
`nickname` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户昵称',
`sex` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '用户性别(1男性,2女性,0未知)',
`country` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户所在国家',
`province` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户所在省份',
`city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户所在城市',
`language` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户的语言(zh_CN)',
`headimgurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户头像',
`subscribe_time` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '关注时间',
`subscribe_at` datetime NULL DEFAULT NULL COMMENT '关注时间',
`remark` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注',
`subscribe_scene` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '扫码关注场景',
`qr_scene` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '二维码场景值',
`qr_scene_str` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '二维码场景内容',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_wechat_fans_openid`(`openid`) USING BTREE,
INDEX `index_wechat_fans_unionid`(`unionid`) USING BTREE,
INDEX `index_wechat_fans_is_back`(`is_black`) USING BTREE,
INDEX `index_wechat_fans_subscribe`(`subscribe`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-粉丝';
-- ----------------------------
-- Table structure for wechat_fans_tags
-- ----------------------------
DROP TABLE IF EXISTS `wechat_fans_tags`;
CREATE TABLE `wechat_fans_tags` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '标签ID',
`appid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
`name` varchar(35) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标签名称',
`count` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '总数',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
INDEX `index_wechat_fans_tags_id`(`id`) USING BTREE,
INDEX `index_wechat_fans_tags_appid`(`appid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-粉丝-标签';
-- ----------------------------
-- Table structure for wechat_keys
-- ----------------------------
DROP TABLE IF EXISTS `wechat_keys`;
CREATE TABLE `wechat_keys` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`appid` char(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '类型(text,image,news)',
`keys` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关键字',
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文本内容',
`image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '图片链接',
`voice_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '语音链接',
`music_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '音乐标题',
`music_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '音乐链接',
`music_image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '缩略图片',
`music_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '音乐描述',
`video_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '视频标题',
`video_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '视频URL',
`video_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '视频描述',
`news_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '图文ID',
`sort` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '排序字段',
`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 `index_wechat_keys_appid`(`appid`) USING BTREE,
INDEX `index_wechat_keys_type`(`type`) USING BTREE,
INDEX `index_wechat_keys_keys`(`keys`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-关键字';
-- ----------------------------
-- Table structure for wechat_media
-- ----------------------------
DROP TABLE IF EXISTS `wechat_media`;
CREATE TABLE `wechat_media` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`appid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号ID',
`md5` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '文件md5',
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '媒体类型',
`media_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '永久素材MediaID',
`local_url` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '本地文件链接',
`media_url` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '远程图片链接',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_wechat_media_appid`(`appid`) USING BTREE,
INDEX `index_wechat_media_md5`(`md5`) USING BTREE,
INDEX `index_wechat_media_type`(`type`) USING BTREE,
INDEX `index_wechat_media_media_id`(`media_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-素材';
-- ----------------------------
-- Table structure for wechat_news
-- ----------------------------
DROP TABLE IF EXISTS `wechat_news`;
CREATE TABLE `wechat_news` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`media_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '永久素材MediaID',
`local_url` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '永久素材显示URL',
`article_id` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '关联图文ID(用英文逗号做分割)',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '是否删除',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `index_wechat_news_artcle_id`(`article_id`) USING BTREE,
INDEX `index_wechat_news_media_id`(`media_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-图文';
-- ----------------------------
-- Table structure for wechat_news_article
-- ----------------------------
DROP TABLE IF EXISTS `wechat_news_article`;
CREATE TABLE `wechat_news_article` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '素材标题',
`local_url` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '永久素材显示URL',
`show_cover_pic` tinyint(4) UNSIGNED NULL DEFAULT 0 COMMENT '显示封面(0不显示,1显示)',
`author` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '文章作者',
`digest` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '摘要内容',
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图文内容',
`content_source_url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '原文地址',
`read_num` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '阅读数量',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-图文-文章';
-- ----------------------------
-- Table structure for wechat_service_config
-- ----------------------------
DROP TABLE IF EXISTS `wechat_service_config`;
CREATE TABLE `wechat_service_config` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`authorizer_appid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号APPID',
`authorizer_access_token` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号授权Token',
`authorizer_refresh_token` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号刷新Token',
`func_info` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号集权',
`nick_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号昵称',
`head_img` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号头像',
`expires_in` bigint(20) NULL DEFAULT NULL COMMENT 'Token有效时间',
`service_type` tinyint(2) NULL DEFAULT NULL COMMENT '微信类型(0代表订阅号,2代表服务号,3代表小程序)',
`service_type_info` tinyint(2) NULL DEFAULT NULL COMMENT '公众号实际类型',
`verify_type` tinyint(2) NULL DEFAULT NULL COMMENT '公众号认证类型(-1代表未认证, 0代表微信认证)',
`verify_type_info` tinyint(2) NULL DEFAULT NULL COMMENT '公众号实际认证类型',
`user_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '众众号原始账号',
`alias` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号别名',
`qrcode_url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公众号二维码',
`business_info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '',
`principal_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '公司名称',
`miniprograminfo` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '小程序JSON',
`idc` tinyint(1) UNSIGNED NULL DEFAULT NULL,
`signature` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '小程序的描述',
`total` bigint(20) UNSIGNED NULL DEFAULT 0 COMMENT '统计调用次数',
`appkey` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '应用接口KEY',
`appuri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '应用接口URI',
`status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(1正常授权,0取消授权)',
`is_deleted` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '删除状态(0未删除,1已删除)',
`create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `index_wechat_service_config_authorizer_appid`(`authorizer_appid`) USING BTREE,
INDEX `index_wechat_service_config_status`(`status`) USING BTREE,
INDEX `index_wechat_service_config_is_deleted`(`is_deleted`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信-授权';
SET FOREIGN_KEY_CHECKS = 1;

180
application/admin/controller/Auth.php

@ -0,0 +1,180 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\service\NodeService;
use library\Controller;
use think\Db;
/**
* 系统权限管理
* Class Auth
* @package app\admin\controller
*/
class Auth extends Controller
{
/**
* 默认数据模型
* @var string
*/
public $table = 'SystemAuth';
/**
* 系统权限管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '系统权限管理';
$query = $this->_query($this->table)->dateBetween('create_at');
$query->like('title,desc')->equal('status')->order('sort desc,id desc')->page();
}
/**
* 权限配置节点
* @auth true
* @throws \ReflectionException
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function apply()
{
$this->title = '权限配置节点';
$auth = $this->request->post('id', '0');
switch (strtolower($this->request->post('action'))) {
case 'get': // 获取权限配置
$checks = Db::name('SystemAuthNode')->where(['auth' => $auth])->column('node');
return $this->success('获取权限节点成功!', NodeService::getAuthTree($checks));
case 'save': // 保存权限配置
list($post, $data) = [$this->request->post(), []];
foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
$data[] = ['auth' => $auth, 'node' => $node];
}
Db::name('SystemAuthNode')->where(['auth' => $auth])->delete();
Db::name('SystemAuthNode')->insertAll($data);
NodeService::applyUserAuth();
return $this->success('权限授权更新成功!');
default:
return $this->_form($this->table, 'apply');
}
}
/**
* 添加系统权限
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function add()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 编辑系统权限
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function edit()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 刷新系统权限
* @auth true
*/
public function refresh()
{
try {
NodeService::applyUserAuth(true);
$this->success('刷新系统授权成功!');
} catch (\think\exception\HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("刷新系统授权失败<br>{$e->getMessage()}");
}
}
/**
* 禁用系统权限
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function forbid()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用系统权限
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function resume()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '1']);
}
/**
* 删除系统权限
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
$this->applyCsrfToken();
$this->_delete($this->table);
}
/**
* 删除结果处理
* @param boolean $result
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
protected function _remove_delete_result($result)
{
if ($result) {
$map = ['auth' => $this->request->post('id')];
Db::name('SystemAuthNode')->where($map)->delete();
$this->success("权限删除成功!", '');
} else {
$this->error("权限删除失败,请稍候再试!");
}
}
}

108
application/admin/controller/Config.php

@ -0,0 +1,108 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use library\Controller;
use think\exception\HttpResponseException;
/**
* 系统参数配置
* Class Config
* @package app\admin\controller
*/
class Config extends Controller
{
/**
* 默认数据模型
* @var string
*/
protected $table = 'SystemConfig';
/**
* 阿里云OSS上传点
* @var array
*/
protected $ossPoints = [
'oss-cn-hangzhou.aliyuncs.com' => '华东 1 杭州',
'oss-cn-shanghai.aliyuncs.com' => '华东 2 上海',
'oss-cn-qingdao.aliyuncs.com' => '华北 1 青岛',
'oss-cn-beijing.aliyuncs.com' => '华北 2 北京',
'oss-cn-zhangjiakou.aliyuncs.com' => '华北 3 张家口',
'oss-cn-huhehaote.aliyuncs.com' => '华北 5 呼和浩特',
'oss-cn-shenzhen.aliyuncs.com' => '华南 1 深圳',
'oss-cn-hongkong.aliyuncs.com' => '香港 1',
'oss-us-west-1.aliyuncs.com' => '美国西部 1 硅谷',
'oss-us-east-1.aliyuncs.com' => '美国东部 1 弗吉尼亚',
'oss-ap-southeast-1.aliyuncs.com' => '亚太东南 1 新加坡',
'oss-ap-southeast-2.aliyuncs.com' => '亚太东南 2 悉尼',
'oss-ap-southeast-3.aliyuncs.com' => '亚太东南 3 吉隆坡',
'oss-ap-southeast-5.aliyuncs.com' => '亚太东南 5 雅加达',
'oss-ap-northeast-1.aliyuncs.com' => '亚太东北 1 日本',
'oss-ap-south-1.aliyuncs.com' => '亚太南部 1 孟买',
'oss-eu-central-1.aliyuncs.com' => '欧洲中部 1 法兰克福',
'oss-eu-west-1.aliyuncs.com' => '英国 1 伦敦',
'oss-me-east-1.aliyuncs.com' => '中东东部 1 迪拜',
];
/**
* 系统参数配置
* @auth true
* @menu true
*/
public function info()
{
$this->title = '系统参数配置';
$this->applyCsrfToken('save');
$this->fetch();
}
/**
* 保存参数到服务器
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function save()
{
$this->applyCsrfToken('save');
$post = $this->request->post();
if (isset($post['storage_type']) && isset($post['storage_local_exts'])) {
$exts = array_unique(explode(',', strtolower($post['storage_local_exts'])));
sort($exts);
if (in_array('php', $exts)) $this->error('禁止上传可执行文件到本地服务器!');
$post['storage_local_exts'] = join(',', $exts);
}
foreach ($post as $key => $value) sysconf($key, $value);
if (isset($post['storage_type']) && $post['storage_type'] === 'oss') {
try {
$local = sysconf('storage_oss_domain');
$bucket = $this->request->post('storage_oss_bucket');
$domain = \library\File::instance('oss')->setBucket($bucket);
if (empty($local) || stripos($local, '.aliyuncs.com') !== false) {
sysconf('storage_oss_domain', $domain);
}
$this->success('阿里云OSS存储动态配置成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("阿里云OSS存储配置失效,{$e->getMessage()}");
}
} else {
$this->success('系统参数配置成功!');
}
}
}

177
application/admin/controller/Index.php

@ -0,0 +1,177 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\service\NodeService;
use library\Controller;
use library\tools\Data;
use think\Console;
use think\Db;
use think\exception\HttpResponseException;
/**
* 系统公共操作
* Class Index
* @package app\admin\controller
*/
class Index extends Controller
{
/**
* 显示后台首页
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index()
{
$this->title = '系统管理后台';
NodeService::applyUserAuth(true);
$this->menus = NodeService::getMenuNodeTree();
if (empty($this->menus) && !NodeService::islogin()) {
$this->redirect('@admin/login');
} else {
$this->fetch();
}
}
/**
* 后台环境信息
*/
public function main()
{
$this->think_ver = \think\App::VERSION;
$this->mysql_ver = Db::query('select version() as ver')[0]['ver'];
$this->fetch();
}
/**
* 修改密码
* @param integer $id
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function pass($id)
{
$this->applyCsrfToken();
if (intval($id) !== intval(session('admin_user.id'))) {
$this->error('只能修改当前用户的密码!');
}
if (!NodeService::islogin()) {
$this->error('需要登录才能操作哦!');
}
if ($this->request->isGet()) {
$this->verify = true;
$this->_form('SystemUser', 'admin@user/pass', 'id', [], ['id' => $id]);
} else {
$data = $this->_input([
'password' => $this->request->post('password'),
'repassword' => $this->request->post('repassword'),
'oldpassword' => $this->request->post('oldpassword'),
], [
'oldpassword' => 'require',
'password' => 'require|min:4',
'repassword' => 'require|confirm:password',
], [
'oldpassword.require' => '旧密码不能为空!',
'password.require' => '登录密码不能为空!',
'password.min' => '登录密码长度不能少于4位有效字符!',
'repassword.require' => '重复密码不能为空!',
'repassword.confirm' => '重复密码与登录密码不匹配,请重新输入!',
]);
$user = Db::name('SystemUser')->where(['id' => $id])->find();
if (md5($data['oldpassword']) !== $user['password']) {
$this->error('旧密码验证失败,请重新输入!');
}
$result = NodeService::checkpwd($data['password']);
if (empty($result['code'])) $this->error($result['msg']);
if (Data::save('SystemUser', ['id' => $user['id'], 'password' => md5($data['password'])])) {
$this->success('密码修改成功,下次请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
/**
* 修改用户资料
* @param integer $id 会员ID
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function info($id = 0)
{
if (!NodeService::islogin()) {
$this->error('需要登录才能操作哦!');
}
$this->applyCsrfToken();
if (intval($id) === intval(session('admin_user.id'))) {
$this->_form('SystemUser', 'admin@user/form', 'id', [], ['id' => $id]);
} else {
$this->error('只能修改登录用户的资料!');
}
}
/**
* 清理运行缓存
* @auth true
*/
public function clearRuntime()
{
if (!NodeService::islogin()) {
$this->error('需要登录才能操作哦!');
}
try {
Console::call('clear');
Console::call('xclean:session');
$this->success('清理运行缓存成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("清理运行缓存失败,{$e->getMessage()}");
}
}
/**
* 压缩发布系统
* @auth true
*/
public function buildOptimize()
{
if (!NodeService::islogin()) {
$this->error('需要登录才能操作哦!');
}
try {
Console::call('optimize:route');
Console::call('optimize:schema');
Console::call('optimize:autoload');
Console::call('optimize:config');
$this->success('压缩发布成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("压缩发布失败,{$e->getMessage()}");
}
}
}

124
application/admin/controller/Login.php

@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\service\NodeService;
use library\Controller;
use think\Db;
/**
* 用户登录管理
* Class Login
* @package app\admin\controller
*/
class Login extends Controller
{
/**
* 后台登录入口
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '系统登录';
if ($this->request->isGet()) {
// 运行环境检查
list($host,) = explode(':', $this->request->host());
if (in_array($host, ['127.0.0.1', 'localhost', 'thinkadmin.top', 'ctolog.com'])) {
$this->devMode = true;
} else {
$this->devMode = false;
}
// 登录状态检查
if (NodeService::islogin()) {
$this->redirect('@admin');
} else {
$this->loginskey = session('loginskey');
if (empty($this->loginskey)) {
$this->loginskey = uniqid();
session('loginskey', $this->loginskey);
}
$this->fetch();
}
} else {
$data = $this->_input([
'username' => $this->request->post('username'),
'password' => $this->request->post('password'),
], [
'username' => 'require|min:4',
'password' => 'require|min:4',
], [
'username.require' => '登录账号不能为空!',
'password.require' => '登录密码不能为空!',
'username.min' => '登录账号长度不能少于4位有效字符!',
'password.min' => '登录密码长度不能少于4位有效字符!',
]);
// 用户信息验证
$map = ['is_deleted' => '0', 'username' => $data['username']];
$user = Db::name('SystemUser')->where($map)->order('id desc')->find();
if (empty($user)) $this->error('登录账号或密码错误,请重新输入!');
if (empty($user['status'])) $this->error('账号已经被禁用,请联系管理员!');
// 账号锁定消息
$cache = cache("user_login_{$user['username']}");
if (is_array($cache) && !empty($cache['number']) && !empty($cache['time'])) {
if ($cache['number'] >= 10 && ($diff = $cache['time'] + 3600 - time()) > 0) {
list($m, $s, $info) = [floor($diff / 60), floor($diff % 60), ''];
if ($m > 0) $info = "{$m} 分";
$this->error("<strong class='color-red'>抱歉,该账号已经被锁定!</strong><p class='nowrap'>连续 10 次登录错误,请 {$info} {$s} 秒后再登录!</p>");
}
}
if (md5($user['password'] . session('loginskey')) !== $data['password']) {
if (empty($cache) || empty($cache['time']) || empty($cache['number']) || $cache['time'] + 3600 < time()) {
$cache = ['time' => time(), 'number' => 1, 'geoip' => $this->request->ip()];
} elseif ($cache['number'] + 1 <= 10) {
$cache = ['time' => time(), 'number' => $cache['number'] + 1, 'geoip' => $this->request->ip()];
}
cache("user_login_{$user['username']}", $cache);
if (($diff = 10 - $cache['number']) > 0) {
$this->error("<strong class='color-red'>登录账号或密码错误!</strong><p class='nowrap'>还有 {$diff} 次尝试机会,将锁定一小时内禁止登录!</p>");
} else {
sysoplog('系统管理', "账号{$user['username']}连续10次登录密码错误,请注意账号安全!");
$this->error("<strong class='color-red'>登录账号或密码错误!</strong><p class='nowrap'>尝试次数达到上限,锁定一小时内禁止登录!</p>");
}
}
// 登录成功并更新账号
cache("user_login_{$user['username']}", null);
Db::name('SystemUser')->where(['id' => $user['id']])->update([
'login_at' => Db::raw('now()'), 'login_ip' => $this->request->ip(), 'login_num' => Db::raw('login_num+1'),
]);
session('loginskey', null);
session('admin_user', $user);
NodeService::applyUserAuth();
sysoplog('系统管理', '用户登录系统成功');
$this->success('登录成功,正在进入系统...', url('@admin'));
}
}
/**
* 退出登录
*/
public function out()
{
\think\facade\Session::clear();
\think\facade\Session::destroy();
$this->success('退出登录成功!', url('@admin/login'));
}
}

162
application/admin/controller/Menu.php

@ -0,0 +1,162 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\service\NodeService;
use library\Controller;
use library\tools\Data;
use think\Db;
/**
* 系统菜单管理
* Class Menu
* @package app\admin\controller
*/
class Menu extends Controller
{
/**
* 当前操作数据库
* @var string
*/
protected $table = 'SystemMenu';
/**
* 系统菜单管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '系统菜单管理';
$this->_page($this->table, false);
}
/**
* 列表数据处理
* @param array $data
*/
protected function _index_page_filter(&$data)
{
foreach ($data as &$vo) {
if ($vo['url'] !== '#') {
$vo['url'] = url($vo['url']) . (empty($vo['params']) ? '' : "?{$vo['params']}");
}
$vo['ids'] = join(',', Data::getArrSubIds($data, $vo['id']));
}
$data = Data::arr2table($data);
}
/**
* 添加系统菜单
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function add()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 编辑系统菜单
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function edit()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 表单数据处理
* @param array $vo
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
protected function _form_filter(&$vo)
{
if ($this->request->isGet()) {
$menus = Db::name($this->table)->where(['status' => '1'])->order('sort desc,id asc')->select();
$menus[] = ['title' => '顶级菜单', 'id' => '0', 'pid' => '-1'];
foreach ($this->menus = Data::arr2table($menus) as $key => &$menu) {
if (substr_count($menu['path'], '-') > 3) unset($this->menus[$key]); # 移除三级以下的菜单
elseif (isset($vo['pid']) && $vo['pid'] !== '' && $cur = "-{$vo['pid']}-{$vo['id']}") {
if (stripos("{$menu['path']}-", "{$cur}-") !== false || $menu['path'] === $cur) unset($this->menus[$key]); # 移除与自己相关联的菜单
}
}
// 选择自己的上级菜单
if (empty($vo['pid']) && $this->request->get('pid', '0')) {
$vo['pid'] = $this->request->get('pid', '0');
}
// 读取系统功能节点
$this->nodes = NodeService::getMenuNodeList();
}
}
/**
* 启用系统菜单
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function resume()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '1']);
}
/**
* 禁用系统菜单
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function forbid()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '0']);
}
/**
* 删除系统菜单
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
$this->applyCsrfToken();
$this->_delete($this->table);
}
}

94
application/admin/controller/Oplog.php

@ -0,0 +1,94 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use library\Controller;
use think\Db;
/**
* 系统日志管理
* Class Oplog
* @package app\admin\controller
*/
class Oplog extends Controller
{
/**
* 指定当前数据表
* @var string
*/
public $table = 'SystemLog';
/**
* 系统操作日志
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index()
{
$this->title = '系统操作日志';
$query = $this->_query($this->table)->like('action,node,content,username,geoip');
$query->dateBetween('create_at')->order('id desc')->page();
}
/**
* 列表数据处理
* @auth true
* @param array $data
* @throws \Exception
*/
protected function _index_page_filter(&$data)
{
$ip = new \Ip2Region();
foreach ($data as &$vo) {
$result = $ip->btreeSearch($vo['geoip']);
$vo['isp'] = isset($result['region']) ? $result['region'] : '';
$vo['isp'] = str_replace(['内网IP', '0', '|'], '', $vo['isp']);
}
}
/**
* 清理系统日志
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function clear()
{
if (Db::name($this->table)->whereRaw('1=1')->delete() !== false) {
$this->success('日志清理成功!');
} else {
$this->error('日志清理失败,请稍候再试!');
}
}
/**
* 删除系统日志
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
$this->applyCsrfToken();
$this->_delete($this->table);
}
}

97
application/admin/controller/Queue.php

@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use library\Controller;
use think\Console;
use think\Db;
/**
* 系统系统任务
* Class Queue
* @package app\admin\controller
*/
class Queue extends Controller
{
/**
* 绑定数据表
* @var string
*/
protected $table = 'SystemJobsLog';
/**
* 系统系统任务
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '系统任务管理';
if (session('admin_user.username') === 'admin') {
$this->cmd = 'php ' . env('root_path') . 'think xtask:start';
$this->message = Console::call('xtask:state')->fetch();
}
$this->uris = Db::name($this->table)->distinct(true)->column('uri');
$query = $this->_query($this->table)->dateBetween('create_at,status_at');
$query->equal('status,title,uri')->order('id desc')->page();
}
/**
* 重置失败任务
* @auth true
*/
public function redo()
{
try {
$where = ['id' => $this->request->post('id')];
$info = Db::name($this->table)->where($where)->find();
if (empty($info)) $this->error('需要重置的任务获取异常!');
$data = isset($info['data']) ? json_decode($info['data'], true) : '[]';
\app\admin\service\QueueService::add($info['title'], $info['uri'], $info['later'], $data, $info['double'], $info['desc']);
$this->success('任务重置成功!', url('@admin') . '#' . url('@admin/queue/index'));
} catch (\think\exception\HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("任务重置失败,请稍候再试!<br> {$e->getMessage()}");
}
}
/**
* 删除系统任务
* @auth true
*/
public function remove()
{
try {
$isNot = false;
foreach (explode(',', $this->request->post('id', '0')) as $id) {
if (!\app\admin\service\QueueService::del($id)) $isNot = true;
}
if (empty($isNot)) $this->_delete($this->table);
$this->success($isNot ? '部分任务删除成功!' : '任务删除成功!');
} catch (\think\exception\HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("任务删除失败,请稍候再试!<br> {$e->getMessage()}");
}
}
}

176
application/admin/controller/User.php

@ -0,0 +1,176 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\admin\service\NodeService;
use library\Controller;
use library\tools\Data;
use think\Db;
/**
* 系统用户管理
* Class User
* @package app\admin\controller
*/
class User extends Controller
{
/**
* 指定当前数据表
* @var string
*/
public $table = 'SystemUser';
/**
* 系统用户管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '系统用户管理';
$query = $this->_query($this->table)->like('username,phone,mail')->equal('status');
$query->dateBetween('login_at,create_at')->where(['is_deleted' => '0'])->order('id desc')->page();
}
/**
* 添加系统用户
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function add()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 编辑系统用户
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function edit()
{
$this->applyCsrfToken();
$this->_form($this->table, 'form');
}
/**
* 修改用户密码
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function pass()
{
$this->applyCsrfToken();
if ($this->request->isGet()) {
$this->verify = false;
$this->_form($this->table, 'pass');
} else {
$post = $this->request->post();
if ($post['password'] !== $post['repassword']) {
$this->error('两次输入的密码不一致!');
}
$result = NodeService::checkpwd($post['password']);
if (empty($result['code'])) $this->error($result['msg']);
if (Data::save($this->table, ['id' => $post['id'], 'password' => md5($post['password'])], 'id')) {
$this->success('密码修改成功,下次请使用新密码登录!', '');
} else {
$this->error('密码修改失败,请稍候再试!');
}
}
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function _form_filter(&$data)
{
if ($this->request->isPost()) {
NodeService::applyUserAuth();
$data['authorize'] = (isset($data['authorize']) && is_array($data['authorize'])) ? join(',', $data['authorize']) : '';
if (isset($data['id'])) {
unset($data['username']);
} elseif (Db::name($this->table)->where(['username' => $data['username']])->count() > 0) {
$this->error('用户账号已经存在,请使用其它账号!');
}
} else {
$data['authorize'] = explode(',', isset($data['authorize']) ? $data['authorize'] : '');
$this->authorizes = Db::name('SystemAuth')->where(['status' => '1'])->order('sort desc,id desc')->select();
}
}
/**
* 禁用系统用户
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function forbid()
{
if (in_array('10000', explode(',', $this->request->post('id')))) {
$this->error('系统超级账号禁止操作!');
}
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用系统用户
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function resume()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '1']);
}
/**
* 删除系统用户
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
if (in_array('10000', explode(',', $this->request->post('id')))) {
$this->error('系统超级账号禁止删除!');
}
$this->applyCsrfToken();
$this->_delete($this->table);
}
}

100
application/admin/controller/api/Plugs.php

@ -0,0 +1,100 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use app\admin\service\NodeService;
use library\Controller;
use library\File;
/**
* 后台插件管理
* Class Plugs
* @package app\admin\controller\api
*/
class Plugs extends Controller
{
/**
* 系统选择器图标
*/
public function icon()
{
$this->title = '图标选择器';
$this->field = input('field', 'icon');
$this->fetch();
}
/**
* Plupload 插件上传文件
* @return \think\response\Json
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function plupload()
{
if (!NodeService::islogin()) {
$this->error('访问授权失败,请重新登录授权再试!');
}
if (!($file = $this->getUploadFile()) || empty($file)) {
return json(['uploaded' => false, 'error' => ['message' => '文件上传异常,文件可能过大或未上传']]);
}
if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
return json(['uploaded' => false, 'error' => ['message' => '文件上传类型受限,请在后台配置']]);
}
if ($file->checkExt('php,sh')) {
return json(['uploaded' => false, 'error' => ['message' => '可执行文件禁止上传到本地服务器']]);
}
$this->safe = boolval(input('safe'));
$this->uptype = $this->getUploadType();
$this->extend = pathinfo($file->getInfo('name'), PATHINFO_EXTENSION);
$name = File::name($file->getPathname(), $this->extend, '', 'md5_file');
$info = File::instance($this->uptype)->save($name, file_get_contents($file->getRealPath()), $this->safe);
if (is_array($info) && isset($info['url'])) {
return json(['uploaded' => true, 'filename' => $name, 'url' => $this->safe ? $name : $info['url']]);
} else {
return json(['uploaded' => false, 'error' => ['message' => '文件处理失败,请稍候再试!']]);
}
}
/**
* 获取文件上传方式
* @return string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function getUploadType()
{
$this->uptype = input('uptype');
if (!in_array($this->uptype, ['local', 'oss', 'qiniu'])) {
$this->uptype = sysconf('storage_type');
}
return $this->uptype;
}
/**
* 获取本地文件对象
* @return \think\File
*/
private function getUploadFile()
{
try {
return $this->request->file('file');
} catch (\Exception $e) {
$this->error(lang($e->getMessage()));
}
}
}

60
application/admin/controller/api/Update.php

@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\controller\api;
use library\command\Sync;
use library\Controller;
/**
* 系统更新接口
* Class Update
* @package app\admin\controller\api
*/
class Update extends Controller
{
/**
* 基础URL地址
* @var string
*/
protected $baseUri = 'https://demo.thinkadmin.top';
/**
* 获取文件列表
*/
public function tree()
{
$sync = new Sync('Update');
$this->success('获取当前文件列表成功!', $sync->build());
}
/**
* 读取线上文件数据
* @param string $encode
*/
public function read($encode)
{
$this->file = env('root_path') . decode($encode);
if (file_exists($this->file)) {
$this->success('读取文件成功!', [
'format' => 'base64',
'content' => base64_encode(file_get_contents($this->file)),
]);
} else {
$this->error('获取文件内容失败!');
}
}
}

124
application/admin/queue/JobsQueue.php

@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\queue;
use app\admin\service\QueueService;
use think\console\Output;
/**
* 基础指令公共类
* Class JobsQueue
* @package app\admin
*/
class JobsQueue
{
/**
* 待处理
*/
const STATUS_PEND = 1;
/**
* 处理中
*/
const STATUS_PROC = 2;
/**
* 处理完成
*/
const STATUS_COMP = 3;
/**
* 处理失败
*/
const STATUS_FAIL = 4;
/**
* 任务ID
* @var integer
*/
protected $id;
/**
* 任务数据
* @var array
*/
protected $data;
/**
* 任务名称
* @var string
*/
protected $title;
/**
* 任务状态
* @var integer
*/
protected $status;
/**
* @var Output
*/
protected $output;
/**
* 任务状态描述
* @var string
*/
protected $statusDesc = '';
/**
* 启动任务处理
* @param \think\queue\Job $job 当前任务对象
* @param array $data 任务执行对象
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function fire(\think\queue\Job $job, $data = [])
{
$this->data = $data;
$this->output = new Output();
$this->id = isset($data['_job_id_']) ? $data['_job_id_'] : '';
$this->title = isset($data['_job_title_']) ? $data['_job_title_'] : '';
$this->output->newLine();
$this->output->writeln(" system task {$this->id} execution start");
$this->output->writeln('---------------------------------------------');
QueueService::status($this->id, self::STATUS_PROC, $this->statusDesc);
if ($this->execute()) {
$this->output->writeln('---------------------------------------------');
$this->output->info(" successful");
$this->status = self::STATUS_COMP;
} else {
$this->output->writeln('---------------------------------------------');
$this->output->error(" failure");
$this->status = self::STATUS_FAIL;
}
$job->delete();
QueueService::status($this->id, $this->status, $this->statusDesc);
$this->output->writeln('---------------------------------------------');
$this->output->newLine();
}
/**
* 执行任务
* @return boolean
*/
protected function execute()
{
return true;
}
}

346
application/admin/service/NodeService.php

@ -0,0 +1,346 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use library\tools\Data;
use library\tools\Node;
use think\Db;
use think\facade\App;
use think\facade\Cache;
use think\facade\Request;
/**
* 功能节点管理服务
* Class NodeService
* @package app\admin\service
*/
class NodeService
{
/**
* 获取标准访问节点
* @param string $node
* @return string
*/
public static function full($node = null)
{
if (empty($node)) return self::current();
if (count(explode('/', $node)) === 1) {
$node = Request::module() . '/' . Request::controller() . '/' . $node;
}
return self::parseString(trim($node, " /"));
}
/**
* 判断是否已经登录
* @return boolean
*/
public static function islogin()
{
return session('admin_user.id') ? true : false;
}
/**
* 获取当前访问节点
* @return string
*/
public static function current()
{
return self::parseString(Request::module() . '/' . Request::controller() . '/' . Request::action());
}
/**
* 检查密码是否合法
* @param string $password
* @return array
*/
public static function checkpwd($password)
{
$password = trim($password);
if (!strlen($password) >= 6) {
return ['code' => 0, 'msg' => '密码必须大于6字符!'];
}
if (!preg_match("/^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,32}$/", $password)) {
return ['code' => 0, 'msg' => '密码必需包含大小写字母、数字、符号任意两者组合!'];
} else {
return ['code' => 1, 'msg' => '密码复杂度通过验证!'];
}
}
/**
* 获取可选菜单节点
* @return array
* @throws \ReflectionException
*/
public static function getMenuNodeList()
{
static $nodes = [];
if (count($nodes) > 0) return $nodes;
foreach (self::getMethodList() as $node => $method) if ($method['menu']) {
$nodes[] = ['node' => $node, 'title' => $method['title']];
}
return $nodes;
}
/**
* 获取系统菜单树数据
* @return array
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function getMenuNodeTree()
{
$list = Db::name('SystemMenu')->where(['status' => '1'])->order('sort desc,id asc')->select();
return self::buildMenuData(Data::arr2tree($list), self::getMethodList());
}
/**
* 后台主菜单权限过滤
* @param array $menus 当前菜单列表
* @param array $nodes 系统权限节点
* @return array
* @throws \ReflectionException
*/
private static function buildMenuData($menus, $nodes)
{
foreach ($menus as $key => &$menu) {
if (!empty($menu['sub'])) $menu['sub'] = self::buildMenuData($menu['sub'], $nodes);
if (!empty($menu['sub'])) $menu['url'] = '#';
elseif (preg_match('/^https?\:/i', $menu['url'])) continue;
elseif ($menu['url'] === '#') unset($menus[$key]);
else {
$node = join('/', array_slice(explode('/', preg_replace('/[\W]/', '/', $menu['url'])), 0, 3));
$menu['url'] = url($menu['url']) . (empty($menu['params']) ? '' : "?{$menu['params']}");
if (!self::checkAuth($node)) unset($menus[$key]);
}
}
return $menus;
}
/**
* 获取授权节点列表
* @return array
* @throws \ReflectionException
*/
public static function getAuthList()
{
static $nodes = [];
if (count($nodes) > 0) return $nodes;
$nodes = Cache::tag('system')->get('NodeAuthList', []);
if (count($nodes) > 0) return $nodes;
foreach (self::getMethodList() as $key => $node) {
if ($node['auth']) $nodes[$key] = $node['title'];
}
Cache::tag('system')->set('NodeAuthList', $nodes);
return $nodes;
}
/**
* 强制验证访问权限
* --- 需要加载对应的控制器
* @param null|string $node
* @return boolean
* @throws \ReflectionException
*/
public static function forceAuth($node = null)
{
if (session('admin_user.username') === 'admin') return true;
$real = is_null($node) ? self::current() : self::full($node);
list($module, $controller, $action) = explode('/', $real);
if (class_exists($class = App::parseClass($module, 'controller', $controller))) {
$reflection = new \ReflectionClass($class);
if ($reflection->hasMethod($action)) {
$comment = preg_replace("/\s/", '', $reflection->getMethod($action)->getDocComment());
if (stripos($comment, '@authtrue') === false) {
return true;
} else {
return in_array($real, (array)session('admin_user.nodes'));
}
}
}
return true;
}
/**
* 检查指定节点授权
* --- 需要读取缓存或扫描所有节点
* @param null|string $node
* @return boolean
* @throws \ReflectionException
*/
public static function checkAuth($node = null)
{
if (session('admin_user.username') === 'admin') return true;
$real = is_null($node) ? self::current() : self::full($node);
if (isset(self::getAuthList()[$real])) {
return in_array($real, (array)session('admin_user.nodes'));
} else {
return true;
}
}
/**
* 获取授权节点列表
* @param array $checkeds
* @return array
* @throws \ReflectionException
*/
public static function getAuthTree($checkeds = [])
{
static $nodes = [];
if (count($nodes) > 0) return $nodes;
foreach (self::getAuthList() as $node => $title) {
$pnode = substr($node, 0, strripos($node, '/'));
$nodes[$node] = ['node' => $node, 'title' => $title, 'pnode' => $pnode, 'checked' => in_array($node, $checkeds)];
}
foreach (self::getClassList() as $node => $title) foreach (array_keys($nodes) as $key) {
if (stripos($key, "{$node}/") !== false) {
$pnode = substr($node, 0, strripos($node, '/'));
$nodes[$node] = ['node' => $node, 'title' => $title, 'pnode' => $pnode, 'checked' => in_array($node, $checkeds)];
$nodes[$pnode] = ['node' => $pnode, 'title' => ucfirst($pnode), 'checked' => in_array($pnode, $checkeds)];
}
}
return $nodes = Data::arr2tree($nodes, 'node', 'pnode', '_sub_');
}
/**
* 初始化用户权限
* @param boolean $force 是否重置系统权限
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function applyUserAuth($force = false)
{
if ($force) {
Cache::tag('system')->rm('NodeAuthList');
Cache::tag('system')->rm('NodeClassData');
Cache::tag('system')->rm('NodeMethodData');
}
if (($uid = session('admin_user.id'))) {
session('admin_user', Db::name('SystemUser')->where(['id' => $uid])->find());
}
if (($aids = session('admin_user.authorize'))) {
$where = [['status', 'eq', '1'], ['id', 'in', explode(',', $aids)]];
$subsql = Db::name('SystemAuth')->field('id')->where($where)->buildSql();
session('admin_user.nodes', array_unique(Db::name('SystemAuthNode')->whereRaw("auth in {$subsql}")->column('node')));
} else {
session('admin_user.nodes', []);
}
}
/**
* 获取控制器节点列表
* @return array
* @throws \ReflectionException
*/
public static function getClassList()
{
static $nodes = [];
if (count($nodes) > 0) return $nodes;
$nodes = Cache::tag('system')->get('NodeClassData', []);
if (count($nodes) > 0) return $nodes;
self::eachController(function (\ReflectionClass $reflection, $prenode) use (&$nodes) {
list($node, $comment) = [trim($prenode, ' / '), $reflection->getDocComment()];
$nodes[$node] = preg_replace('/^\/\*\*\*(.*?)\*.*?$/', '$1', preg_replace("/\s/", '', $comment));
if (stripos($nodes[$node], '@') !== false) $nodes[$node] = '';
});
Cache::tag('system')->set('NodeClassData', $nodes);
return $nodes;
}
/**
* 获取方法节点列表
* @return array
* @throws \ReflectionException
*/
public static function getMethodList()
{
static $nodes = [];
if (count($nodes) > 0) return $nodes;
$nodes = Cache::tag('system')->get('NodeMethodData', []);
if (count($nodes) > 0) return $nodes;
self::eachController(function (\ReflectionClass $reflection, $prenode) use (&$nodes) {
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
$action = strtolower($method->getName());
list($node, $comment) = ["{$prenode}{$action}", preg_replace("/\s/", '', $method->getDocComment())];
$nodes[$node] = [
'auth' => stripos($comment, '@authtrue') !== false,
'menu' => stripos($comment, '@menutrue') !== false,
'title' => preg_replace('/^\/\*\*\*(.*?)\*.*?$/', '$1', $comment),
];
if (stripos($nodes[$node]['title'], '@') !== false) $nodes[$node]['title'] = '';
}
});
Cache::tag('system')->set('NodeMethodData', $nodes);
return $nodes;
}
/**
* 控制器扫描回调
* @param callable $callable
* @throws \ReflectionException
*/
public static function eachController($callable)
{
foreach (self::scanPath(env('app_path') . "*/controller/") as $file) {
if (!preg_match("|/(\w+)/controller/(.+)\.php$|", $file, $matches)) continue;
list($module, $controller) = [$matches[1], strtr($matches[2], '/', '.')];
if (class_exists($class = substr(strtr(env('app_namespace') . $matches[0], '/', '\\'), 0, -4))) {
call_user_func($callable, new \ReflectionClass($class), Node::parseString("{$module}/{$controller}/"));
}
}
}
/**
* 驼峰转下划线规则
* @param string $node 节点名称
* @return string
*/
public static function parseString($node)
{
if (count($nodes = explode('/', $node)) > 1) {
$dots = [];
foreach (explode('.', $nodes[1]) as $dot) {
$dots[] = trim(preg_replace("/[A-Z]/", "_\\0", $dot), "_");
}
$nodes[1] = join('.', $dots);
}
return strtolower(join('/', $nodes));
}
/**
* 获取所有PHP文件
* @param string $dirname 扫描目录
* @param array $data 额外数据
* @param string $ext 有文件后缀
* @return array
*/
private static function scanPath($dirname, $data = [], $ext = 'php')
{
foreach (glob("{$dirname}*") as $file) {
if (is_dir($file)) {
$data = array_merge($data, self::scanPath("{$file}/"));
} elseif (is_file($file) && pathinfo($file, 4) === $ext) {
$data[] = str_replace('\\', '/', $file);
}
}
return $data;
}
}

53
application/admin/service/OplogService.php

@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use library\tools\Node;
use think\Db;
/**
* 系统日志服务管理
* Class LogService
* @package app\admin\service
*/
class OplogService
{
/**
* 写入操作日志
* @param string $action
* @param string $content
* @return bool
*/
public static function write($action = '行为', $content = "内容描述")
{
return Db::name('SystemLog')->insert([
'node' => Node::current(), 'action' => $action, 'content' => $content,
'geoip' => PHP_SAPI === 'cli' ? '127.0.0.1' : request()->ip(),
'username' => PHP_SAPI === 'cli' ? 'cli' : (string)session('admin_user.username'),
]);
}
/**
* 清理系统日志
* @return boolean
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function clear()
{
return Db::name('SystemLog')->where('1=1')->delete() !== false;
}
}

130
application/admin/service/QueueService.php

@ -0,0 +1,130 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\admin\service;
use think\Db;
/**
* 任务管理器
* Class QueueService
* @package app\admin\service
*/
class QueueService
{
/**
* 待处理
*/
const STATUS_PEND = 1;
/**
* 处理中
*/
const STATUS_PROC = 2;
/**
* 处理完成
*/
const STATUS_COMP = 3;
/**
* 处理失败
*/
const STATUS_FAIL = 4;
/**
* 创建任务并记录日志
* @param string $title 任务名称
* @param string $uri 任务命令
* @param integer $later 延时时间
* @param array $data 任务附加数据
* @param integer $double 任务多开
* @param string $desc 任务描述
* @throws \think\Exception
*/
public static function add($title, $uri, $later, array $data, $double = 1, $desc = '')
{
if (empty($double) && self::exists($title)) {
throw new \think\Exception('该任务已经创建,请耐心等待处理完成!');
}
$jobId = Db::name('SystemJobsLog')->insertGetId([
'title' => $title, 'later' => $later, 'uri' => $uri, 'double' => intval($double),
'data' => json_encode($data, 256), 'desc' => $desc, 'status_at' => date('Y-m-d H:i:s'),
]);
$data['_job_id_'] = $jobId;
$data['_job_title_'] = $title;
\think\Queue::later($later, $uri, $data);
}
/**
* 更新任务状态
* @param integer $jobId
* @param integer $status
* @param string $statusDesc
* @return boolean
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function status($jobId, $status = self::STATUS_PEND, $statusDesc = '')
{
$result = Db::name('SystemJobsLog')->where(['id' => $jobId])->update([
'status' => $status, 'status_desc' => $statusDesc, 'status_at' => date('Y-m-d H:i:s'),
]);
return $result !== false;
}
/**
* 检查任务是否存在
* @param string $title
* @return boolean
*/
public static function exists($title)
{
$where = [['title', 'eq', $title], ['status', 'in', [1, 2]]];
return Db::name('SystemJobsLog')->where($where)->count() > 0;
}
/**
* 获取任务数据
* @param integer $jobId
* @return array|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function get($jobId)
{
return Db::name('SystemJobsLog')->where(['id' => $jobId])->find();
}
/**
* 删除任务数据
* @param integer $jobId
* @return boolean
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function del($jobId)
{
$where = [['id', 'eq', $jobId], ['status', 'in', [1, 3, 4]]];
if (Db::name('SystemJobsLog')->where($where)->delete() > 0) {
Db::name('SystemJobs')->whereLike('payload', '%"_job_id_":"' . $jobId . '"%')->delete();
return true;
} else {
return false;
}
}
}

119
application/admin/sys.php

@ -0,0 +1,119 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
use app\admin\service\NodeService;
use app\admin\service\OplogService;
use library\File;
use think\Db;
use think\facade\Middleware;
use think\Request;
if (!function_exists('auth')) {
/**
* 节点访问权限检查
* @param string $node
* @return boolean
* @throws ReflectionException
*/
function auth($node)
{
return NodeService::checkAuth($node);
}
}
if (!function_exists('sysdata')) {
/**
* JSON 数据读取与存储
* @param string $name 数据名称
* @param array|null $value 数据内容
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
function sysdata($name, array $value = null)
{
if (is_null($value)) {
$data = json_decode(Db::name('SystemData')->where(['name' => $name])->value('value'), true);
return empty($data) ? [] : $data;
} else {
return data_save('SystemData', ['name' => $name, 'value' => json_encode($value, JSON_UNESCAPED_UNICODE)], 'name');
}
}
}
if (!function_exists('sysoplog')) {
/**
* 写入系统日志
* @param string $action 日志行为
* @param string $content 日志内容
* @return boolean
*/
function sysoplog($action, $content)
{
return OplogService::write($action, $content);
}
}
if (!function_exists('local_image')) {
/**
* 下载远程文件到本地
* @param string $url 远程图片地址
* @return string
*/
function local_image($url)
{
$result = File::down($url);
if (isset($result['url'])) {
return $result['url'];
} else {
return $url;
}
}
}
if (!function_exists('base64_image')) {
/**
* base64 图片上传接口
* @param string $content
* @param string $predir
* @return string
*/
function base64_image($content, $predir = 'base64/')
{
try {
if (preg_match('|^data:image/(.*?);base64,|i', $content)) {
list($ext, $base) = explode('|||', preg_replace('|^data:image/(.*?);base64,|i', '$1|||', $content));
$info = File::save($predir . md5($base) . '.' . (empty($ext) ? 'tmp' : $ext), base64_decode($base));
return $info['url'];
} else {
return $content;
}
} catch (\Exception $e) {
return $content;
}
}
}
// 访问权限检查中间键
Middleware::add(function (Request $request, \Closure $next) {
// 验证访问节点权限
if (NodeService::forceAuth()) {
return $next($request);
} elseif (NodeService::islogin()) {
return json(['code' => 0, 'msg' => '抱歉,没有访问该操作的权限!']);
} else {
return json(['code' => 0, 'msg' => '抱歉,需要登录获取访问权限!', 'url' => url('@admin/login')]);
}
});

3659
application/admin/view/api/plugs/icon.html

File diff suppressed because it is too large

116
application/admin/view/auth/apply.html

@ -0,0 +1,116 @@
{extend name='main'}
{block name="button"}
{if auth("admin/auth/refresh")}
<button data-load='{:url("refresh")}' class='layui-btn layui-btn-sm layui-btn-primary'>刷新权限</button>
{/if}
{/block}
{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>
window.RoleAction = new function () {
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 ? RoleAction.ztree.checkNode(node, !node.checked, null, true) : RoleAction.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 (that) {
var index = $.msg.loading();
$.form.load('{:url()}', {id: '{$vo.id}', action: 'get'}, 'post', function (ret) {
that.data = that.renderChildren(ret.data, 1);
return $.msg.close(index), 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()}', {id: '{$vo.id}', action: 'save', nodes: nodes}, 'post');
};
// 刷新数据
this.getData(this);
// 提交表单
$('[data-submit-role]').on('click', function () {
RoleAction.submit();
});
};
</script>
{/block}
{block name="style"}
<link href="__ROOT__/static/plugs/ztree/zTreeStyle/zTreeStyle.css" rel="stylesheet">
<script src="__ROOT__/static/plugs/ztree/ztree.all.min.js"></script>
<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}

22
application/admin/view/auth/form.html

@ -0,0 +1,22 @@
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">权限名称</label>
<div class="layui-input-block">
<input type="text" name="title" value='{$vo.title|default=""}' required placeholder="请输入权限名称" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">权限描述</label>
<div class="layui-input-block">
<textarea placeholder="请输入权限描述" required class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
</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>

80
application/admin/view/auth/index.html

@ -0,0 +1,80 @@
{extend name='main'}
{block name="button"}
{if auth("admin/auth/add")}
<button data-modal='{:url("add")}' data-title="添加权限" class='layui-btn layui-btn-sm layui-btn-primary'>添加权限</button>
{/if}
{if auth("admin/auth/remove")}
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('admin/auth/remove')}" 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 class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
</th>
<th class='text-left nowrap'>权限信息</th>
<th class='text-left nowrap'>创建时间</th>
<th class="text-center nowrap">使用状态</th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick>
<td class='list-table-check-td think-checkbox'>
<label><input class="list-check-box" value='{$vo.id}' type='checkbox'></label>
</td>
<td class='text-left'>
权限名称:{$vo.title|default='-'}<br>
<p class="color-desc">权限描述:{$vo.desc|default="没有写描述哦!"}</p>
</td>
<td class="text-left nowrap">
日期:{$vo.create_at|format_datetime|str_replace=' ','<br><span class="color-desc">时间:',###|raw}</span>
</td>
<td class='text-center nowrap'>
{eq name='vo.status' value='0'}<span class="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}
</td>
<td class='text-center nowrap'>
{if auth("admin/auth/edit")}
<span class="text-explode">|</span>
<a data-dbclick class="layui-btn layui-btn-sm" data-title="编辑权限" data-modal='{:url("admin/auth/edit")}?id={$vo.id}'>编 辑</a>
{/if}
{if auth("admin/auth/apply")}
<a class="layui-btn layui-btn-normal layui-btn-sm" data-open='{:url("admin/auth/apply")}?id={$vo.id}'>授 权</a>
{/if}
{if $vo.status eq 1 and auth("admin/auth/forbid")}
<a class="layui-btn layui-btn-warm layui-btn-sm" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0" data-csrf="{:systoken('admin/auth/forbid')}">禁 用</a>
{elseif $vo.status eq 0 and auth("admin/auth/resume")}
<a class="layui-btn layui-btn-warm layui-btn-sm" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1" data-csrf="{:systoken('admin/auth/resume')}">启 用</a>
{/if}
{if auth("admin/auth/remove")}
<a class="layui-btn layui-btn-danger layui-btn-sm" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/auth/remove')}">删 除</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

42
application/admin/view/auth/index_search.html

@ -0,0 +1,42 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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="{$Think.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="{$Think.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">
{foreach [''=>'-- 全部状态 --','0'=>'已禁用的权限','1'=>'使用中的权限'] as $k=>$v}
{eq name='Think.get.status' value='$k.""'}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/eq}
{/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="{$Think.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>
<script>form.render()</script>

21
application/admin/view/config/info-storage-local.html

@ -0,0 +1,21 @@
<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body">
<div class="padding-right-40">
<div class="color-blue padding-left-40 padding-bottom-20">
文件将存储在本地服务器,需确保服务器的 public/upload 目录有写入权限,有足够的存储空间。
</div>
<div class="layui-form-item">
<label class="layui-form-label">AllowExts<br><span class="nowrap color-desc">允许类型</span></label>
<div class="layui-input-block">
<input type="text" name="storage_local_exts" required value="{:sysconf('storage_local_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
<p class="help-block">设置系统允许上传文件的后缀,多个以英文逗号隔开。如:png,jpg,rar,doc</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<div class="layui-form-item text-center">
<input type="hidden" name="storage_type" value="local">
<button class="layui-btn" type="submit">保存配置</button>
</div>
</div>
</div>
</form>

79
application/admin/view/config/info-storage-oss.html

@ -0,0 +1,79 @@
<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body">
<div class="padding-right-40">
<div class="color-blue padding-left-40 padding-bottom-20">
文件将上传到阿里云OSS空间,需要配置OSS公开访问及跨域策略(目前已实现自动创建空间及配置访问策略)。
</div>
<div class="layui-form-item">
<label class="layui-form-label">AllowExts<br><span class="nowrap color-desc">允许类型</span></label>
<div class="layui-input-block">
<input type="text" name="storage_local_exts" required value="{:sysconf('storage_local_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
<p class="help-block">设置系统允许上传文件的后缀,多个以英文逗号隔开。如:png,jpg,rar,doc</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label label-required">Protocol<br><span class="nowrap color-desc">访问协议</span></label>
<div class="layui-input-block">
<!--{foreach ['http','https','auto'] as $pro}-->
<label class="think-radio">
<!--{if sysconf('storage_oss_is_https') eq $pro}-->
<input checked type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
<!--{else}-->
<input type="radio" name="storage_oss_is_https" value="{$pro}" lay-ignore> {$pro}
<!--{/if}-->
</label>
<!--{/foreach}-->
<p class="help-block">阿里云对象存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Bucket<br><span class="nowrap color-desc">空间名称</span></label>
<div class="layui-input-block">
<input type="text" name="storage_oss_bucket" required value="{:sysconf('storage_oss_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">EndPoint<br><span class="nowrap color-desc">数据中心</span></label>
<div class="layui-input-block">
<select required name="storage_oss_endpoint" class="layui-select" lay-search>
{foreach $ossPoints as $k=>$p}
<!--{if sysconf('storage_oss_endpoint') eq $k}-->
<option selected value="{$k}">{$p} <span class="font-s10 color-desc">({$k})</span></option>
<!--{else}-->
<option value="{$k}">{$p} <span class="font-s10 color-desc">({$k})</span></option>
<!--{/if}-->
{/foreach}
</select>
<p class="help-block">请选择OSS数据中心访问节点,有效值如:oss-cn-shenzhen.aliyuncs.com</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">AccessKey<br><span class="nowrap color-desc">访问密钥</span></label>
<div class="layui-input-block">
<input type="text" name="storage_oss_keyid" required value="{:sysconf('storage_oss_keyid')}" maxlength="16" placeholder="请输入OSS AccessKey (访问密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">SecretKey<br><span class="nowrap color-desc">安全密钥</span></label>
<div class="layui-input-block">
<input type="text" name="storage_oss_secret" required value="{:sysconf('storage_oss_secret')}" maxlength="30" placeholder="请输入OSS SecretKey (安全密钥)" class="layui-input">
<p class="help-block">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Domain<br><span class="nowrap color-desc">访问域名</span></label>
<div class="layui-input-block">
<input type="text" name="storage_oss_domain" value="{:sysconf('storage_oss_domain')}" placeholder="请输入OSS存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写OSS存储外部访问域名,如:think-admin-oss.oss-cn-shenzhen.aliyuncs.com(正常情况下是自动获取的)</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<div class="layui-form-item text-center">
<input type="hidden" name="storage_type" value="oss">
<button class="layui-btn" type="submit">保存配置</button>
</div>
</div>
</div>
</form>

80
application/admin/view/config/info-storage-qiniu.html

@ -0,0 +1,80 @@
<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body">
<div class="padding-right-40">
<div class="color-blue padding-left-40 padding-bottom-20">
文件将上传到七牛云空间(<a target="_blank" href="https://portal.qiniu.com/signup?code=3lhz6nmnwbple">点击这里免费申请10G存储</a>),申请成功后添加公开bucket并配置接口密钥。
</div>
<div class="layui-form-item">
<label class="layui-form-label">AllowExts<br><span class="nowrap color-desc">允许类型</span></label>
<div class="layui-input-block">
<input type="text" name="storage_local_exts" required value="{:sysconf('storage_local_exts')}" placeholder="请输入系统文件上传后缀" class="layui-input">
<p class="help-block">设置系统允许上传文件的后缀,多个以英文逗号隔开。如:png,jpg,rar,doc</p>
</div>
</div>
<div class="layui-form-item" data-storage-type="qiniu">
<label class="layui-form-label label-required">Protocol<br><span class="nowrap color-desc">访问协议</span></label>
<div class="layui-input-block">
<!--{foreach ['http','https','auto'] as $pro}-->
<label class="think-radio">
<!--{if sysconf('storage_qiniu_is_https') eq $pro}-->
<input checked type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
<!--{else}-->
<input type="radio" name="storage_qiniu_is_https" value="{$pro}" lay-ignore> {$pro}
<!--{/if}-->
</label>
<!--{/foreach}-->
<p class="help-block">七牛云存储访问协议(http、https、auto),其中 https 需要配置证书才能使用,auto 为相对协议自动根据域名切换http与https。</p>
</div>
</div>
<div class="layui-form-item" data-storage-type="qiniu">
<label class="layui-form-label">Region<br><span class="nowrap color-desc label-required">存储区域</span></label>
<div class="layui-input-block">
{foreach ['华东','华北','华南','北美'] as $area}
<label class="think-radio">
<!--{if sysconf('storage_qiniu_region') eq $area}-->
<input checked type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
<!--{else}-->
<input type="radio" name="storage_qiniu_region" value="{$area}" lay-ignore>
<!--{/if}-->
{$area}
</label>
{/foreach}
<p class="help-block">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件。</p>
</div>
</div>
<div class="layui-form-item" data-storage-type="qiniu">
<label class="layui-form-label">Bucket<br><span class="nowrap color-desc">空间名称</span></label>
<div class="layui-input-block">
<input 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" data-storage-type="qiniu">
<label class="layui-form-label">Domain<br><span class="nowrap color-desc">访问域名</span></label>
<div class="layui-input-block">
<input type="text" name="storage_qiniu_domain" required value="{:sysconf('storage_qiniu_domain')}" placeholder="请输入七牛云存储 Domain (访问域名)" class="layui-input">
<p class="help-block">填写七牛云存储访问域名,如:static.ctolog.cc</p>
</div>
</div>
<div class="layui-form-item" data-storage-type="qiniu">
<label class="layui-form-label">AccessKey<br><span class="nowrap color-desc">访问密钥</span></label>
<div class="layui-input-block">
<input 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" data-storage-type="qiniu">
<label class="layui-form-label">SecretKey<br><span class="nowrap color-desc">安全密钥</span></label>
<div class="layui-input-block">
<input 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>
<div class="layui-form-item text-center">
<input type="hidden" name="storage_type" value="qiniu">
<button class="layui-btn" type="submit">保存配置</button>
</div>
</div>
</div>
</form>

32
application/admin/view/config/info-storage.html

@ -0,0 +1,32 @@
<div class="layui-card layui-form">
<div class="layui-card-body">
<div class="layui-form-item padding-top-20">
<label class="layui-form-label">Storage<br><span class="nowrap color-desc">存储类型</span></label>
<div class="layui-input-block">
{foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','oss'=>'阿里云OSS存储'] as $k=>$v}
<input type="radio" data-storagetype="{$k}" name="storage_type" value="{$k}" title="{$v}" lay-filter="storage_type">
{/foreach}
<p class="help-block">请选择文件存储类型,其它云储存需要配置正确的参数才可以上传文件哦!</p>
</div>
</div>
</div>
</div>
<div class="padding-bottom-10">
<div data-type="oss">{include file='config/info-storage-oss'}</div>
<div data-type="local">{include file='config/info-storage-local'}</div>
<div data-type="qiniu">{include file='config/info-storage-qiniu'}</div>
</div>
<script>
apply('{:sysconf("storage_type")}');
form.render().on('radio(storage_type)', function (data) {
apply(data.value);
});
function apply(value) {
this.$active = $("[data-storagetype='" + value + "']").trigger('click');
if (this.$active.size() < 1) $("[data-storagetype]:first").trigger('click');
$('[data-type="' + value + '"]').show().siblings('[data-type]').hide();
}
</script>

54
application/admin/view/config/info-website.html

@ -0,0 +1,54 @@
<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
<div class="layui-card-body">
<div class="padding-right-40 padding-bottom-10 margin-top-20">
<div class="layui-form-item">
<label class="layui-form-label">Name<br><span class="nowrap color-desc">程序名称</span></label>
<div class="layui-input-block">
<input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
<p class="help-block">当前程序名称,在后台主标题上显示 {:sysconf('app_name')}</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Version<br><span class="nowrap color-desc">程序版本</span></label>
<div class="layui-input-block">
<input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
<p class="help-block">当前程序版本号,在后台主标题上标显示版本 {:sysconf('app_version')}</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Website<br><span class="nowrap color-desc">网站名称</span></label>
<div class="layui-input-block">
<input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
<p class="help-block">网站名称,将在浏览器的标签上显示 {:sysconf('site_name')}</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Browser<br><span class="nowrap color-desc">浏览器图标</span></label>
<div class="layui-input-block">
<img alt="icon" data-tips-image style="height:auto;max-height:32px;min-width:32px" src="{:sysconf('site_icon')}"/>
<input type="hidden" name="site_icon" onchange="$(this).prev('img').attr('src', this.value)" value="{:sysconf('site_icon')}" class="layui-input">
<a class="margin-left-10" data-file="btn" data-type="ico,png" data-field="site_icon">上传图片</a>
<p class="help-block">建议上传 ICO 图标的尺寸为 128x128px,此图标用于网站标题前,<a href="http://www.favicon-icon-generator.com/" target="_blank">ICON在线制作</a></p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Copyright<br><span class="nowrap color-desc">版权信息</span></label>
<div class="layui-input-block">
<input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
<p class="help-block">程序的版权信息设置,在后台登录页面显示版本信息</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Miitbeian<br><span class="nowrap color-desc">网站备案号</span></label>
<div class="layui-input-block">
<input name="miitbeian" placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
<p class="help-block">网站备案号,可以在<a target="_blank" href="http://www.miitbeian.gov.cn">备案管理中心</a>查询获取,将在登录页面下面显示</p>
</div>
</div>
<div class="hr-line-dashed margin-left-40"></div>
<div class="layui-form-item text-center padding-bottom-10">
<button class="layui-btn" type="submit">保存配置</button>
</div>
</div>
</div>
</form>

29
application/admin/view/config/info.html

@ -0,0 +1,29 @@
{extend name="main"}
{block name="content"}
<div class="layui-tab layui-tab-card think-bg-white">
<ul class="layui-tab-title notselect">
<li data-type='website'>网站参数设置</li>
<li data-type="storage">文件存储配置</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item">{include file='config/info-website'}</div>
<div class="layui-tab-item">{include file='config/info-storage'}</div>
</div>
</div>
<script>
(function (storage) {
(function (type, $default, $checked) {
$default = $('.layui-tab ul.layui-tab-title li:first');
$checked = $('.layui-tab ul.layui-tab-title li[data-type="' + type + '"]');
($checked.length > 0 ? $checked : $default).trigger('click');
})(layui.data(storage)['type'] || '');
$('.layui-tab ul.layui-tab-title li[data-type]').on('click', function () {
layui.data(storage, {key: 'type', value: this.getAttribute('data-type')});
});
})('website-config-type');
</script>
{/block}

125
application/admin/view/index/index.html

@ -0,0 +1,125 @@
<!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="shortcut icon" href="{:sysconf('site_icon')}">
<link rel="stylesheet" href="__ROOT__/static/plugs/awesome/fonts.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
{block name="style"}{/block}
<script>window.ROOT_URL = '__ROOT__';</script>
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
</head>
<body class="layui-layout-body">
{block name='body'}
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
<!-- 顶部菜单 开始 -->
<div class="layui-header notselect">
<a href="{:url('@')}" class="layui-logo layui-elip">
{:sysconf('app_name')} {if sysconf('app_version')}<sup class="padding-left-5">{:sysconf('app_version')}</sup>{/if}
</a>
<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>
{foreach $menus as $oneMenu}
<li class="layui-nav-item">
<a data-menu-node="m-{$oneMenu.id}" data-open="{$oneMenu.url}">
{notempty name='oneMenu.icon'}<span class='{$oneMenu.icon} padding-right-5'></span>{/notempty}
<span>{$oneMenu.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>
{notempty name='Think.session.admin_user.username'}
<li class="layui-nav-item">
<dl class="layui-nav-child">
<dd lay-unselect><a data-modal="{:url('admin/index/info',['id'=>session('admin_user.id')])}"><i class="layui-icon layui-icon-set-fill margin-right-5"></i>基本资料</a></dd>
<dd lay-unselect><a data-modal="{:url('admin/index/pass',['id'=>session('admin_user.id')])}"><i class="layui-icon layui-icon-component margin-right-5"></i>安全设置</a></dd>
{if auth('admin/index/buildoptimize')}
<dd lay-unselect><a data-modal="{:url('admin/index/buildOptimize')}"><i class="layui-icon layui-icon-template-1 margin-right-5"></i>压缩发布</a></dd>
{/if}
{if auth('admin/index/clearruntime')}
<dd lay-unselect><a data-modal="{:url('admin/index/clearRuntime')}"><i class="layui-icon layui-icon-fonts-clear margin-right-5"></i>清理缓存</a></dd>
{/if}
<dd lay-unselect><a data-confirm="确定要退出登录吗?" data-load="{:url('admin/login/out')}"><i class="layui-icon layui-icon-release margin-right-5"></i>退出登录</a></dd>
</dl>
<a><span><i class="layui-icon layui-icon-username margin-right-5"></i> {:session('admin_user.username')}</span></a>
</li>
{else}
<li class="layui-nav-item">
<a data-href="{:url('@admin/login')}"><i class="layui-icon layui-icon-username"></i> 立即登录</a>
</li>
{/notempty}
</ul>
</div>
<!-- 顶部菜单 结束 -->
<!-- 左则菜单 开始 -->
<div class="layui-side layui-bg-black notselect">
<div class="layui-side-scroll">
{foreach $menus as $oneMenu}
{notempty name='oneMenu.sub'}
<ul class="layui-nav layui-nav-tree layui-hide" data-menu-layout="m-{$oneMenu.id}">
{foreach $oneMenu.sub as $twoMenu}
{empty name='twoMenu.sub'}
<li class="layui-nav-item">
<a data-target-tips="{$twoMenu.title}" data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}" data-open="{$twoMenu.url}">
<span class='{$twoMenu.icon|default="layui-icon layui-icon-link"}'></span>
<span class="nav-text padding-left-5">{$twoMenu.title}</span>
</a>
</li>
{else}
<li class="layui-nav-item" data-submenu-layout='m-{$oneMenu.id}-{$twoMenu.id}'>
<a data-target-tips="{$twoMenu.title}" style="background:#393D49">
<span class='nav-icon layui-hide {$twoMenu.icon|default="layui-icon layui-icon-triangle-d"}'></span>
<span class="nav-text padding-left-5">{$twoMenu.title}</span>
</a>
<dl class="layui-nav-child">
{foreach $twoMenu.sub as $thrMenu}
<dd>
<a data-target-tips="{$thrMenu.title}" data-open="{$thrMenu.url}" data-menu-node="m-{$oneMenu.id}-{$twoMenu.id}-{$thrMenu.id}">
<span class='nav-icon padding-left-5 {$thrMenu.icon|default="layui-icon layui-icon-link"}'></span>
<span class="nav-text padding-left-5">{$thrMenu.title}</span>
</a>
</dd>
{/foreach}
</dl>
</li>
{/empty}
{/foreach}
</ul>
{/notempty}
{/foreach}
</div>
</div>
<!-- 左则菜单 结束 -->
<!-- 主体内容 开始 -->
<div class="layui-body layui-bg-gray">{block name='content'}{/block}</div>
<!-- 主体内容 结束 -->
</div>
{/block}
<script src="__ROOT__/static/plugs/layui/layui.all.js"></script>
<script src="__ROOT__/static/plugs/require/require.js"></script>
<script src="__ROOT__/static/admin.js"></script>
{block name='script'}{/block}
</body>
</html>

207
application/admin/view/index/main.html

@ -0,0 +1,207 @@
{extend name='main'}
{block name='content'}
<style>
.store-total-container {
font-size: 14px;
margin-bottom: 20px;
letter-spacing: 1px;
}
.store-total-container .store-total-icon {
top: 45%;
right: 8%;
font-size: 65px;
position: absolute;
color: rgba(255, 255, 255, 0.4);
}
.store-total-container .store-total-item {
color: #fff;
line-height: 4em;
padding: 15px 25px;
position: relative;
}
.store-total-container .store-total-item > div:nth-child(2) {
font-size: 46px;
line-height: 46px;
}
</style>
<div class="think-box-shadow store-total-container notselect">
<div class="margin-bottom-15">商城统计</div>
<div class="layui-row layui-col-space15">
<div class="layui-col-sm6 layui-col-md3">
<div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#57bdbf,#2f9de2)">
<div>商品总量</div>
<div>63</div>
<div>当前商品总数量</div>
</div>
<i class="store-total-icon layui-icon layui-icon-template-1"></i>
</div>
<div class="layui-col-sm6 layui-col-md3">
<div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#ff7d7d,#fb2c95)">
<div>用户总量</div>
<div>1,634</div>
<div>当前用户总数量</div>
</div>
<i class="store-total-icon layui-icon layui-icon-user"></i>
</div>
<div class="layui-col-sm6 layui-col-md3">
<div class="store-total-item nowrap" style="background:linear-gradient(-113deg,#c543d8,#925cc3)">
<div>订单总量</div>
<div>148</div>
<div>已付款订单总数量</div>
</div>
<i class="store-total-icon layui-icon layui-icon-read"></i>
</div>
<div class="layui-col-sm6 layui-col-md3">
<div class="store-total-item nowrap" style="background:linear-gradient(-141deg,#ecca1b,#f39526)">
<div>评价总量</div>
<div>0</div>
<div>订单评价总数量</div>
</div>
<i class="store-total-icon layui-icon layui-icon-survey"></i>
</div>
</div>
</div>
<div class="think-box-shadow store-total-container">
<div class="margin-bottom-15">实时概况</div>
<div class="layui-row layui-col-space15">
<div class="layui-col-md6 margin-bottom-15">
<div class="layui-row">
<div class="layui-col-xs3 text-center">
<i class="layui-icon color-blue" style="font-size:60px;line-height:72px">&#xe65e;</i>
</div>
<div class="layui-col-xs4">
<div class="font-s14">销售额(元)</div>
<div class="font-s16">1351.00</div>
<div class="font-s12 color-desc">昨日:974.00</div>
</div>
<div class="layui-col-xs5">
<div class="font-s14">支付订单数</div>
<div class="font-s16">106</div>
<div class="font-s12 color-desc">昨日:76</div>
</div>
</div>
</div>
<div class="layui-col-md6 margin-bottom-15">
<div class="layui-row">
<div class="layui-col-xs3 text-center">
<i class="layui-icon color-blue" style="font-size:60px;line-height:72px">&#xe663;</i>
</div>
<div class="layui-col-xs4">
<div class="font-s14">新增用户数</div>
<div class="font-s16">327</div>
<div class="font-s12 color-desc">昨日:238</div>
</div>
<div class="layui-col-xs5">
<div class="font-s14">下单用户数</div>
<div class="font-s16">69</div>
<div class="font-s12 color-desc">昨日:34</div>
</div>
</div>
</div>
</div>
</div>
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<div class="think-box-shadow">
<table class="layui-table" lay-skin="line" lay-even>
<caption class="text-left margin-bottom-15 font-s14">系统信息</caption>
<colgroup>
<col width="30%">
</colgroup>
<tbody>
<tr>
<td>当前程序版本</td>
<td>{:sysconf('app_version')}</td>
</tr>
<tr>
<td>运行PHP版本</td>
<td>{$Think.PHP_VERSION}</td>
</tr>
<tr>
<td>ThinkPHP版本</td>
<td>{$think_ver}</td>
</tr>
<tr>
<td>MySQL数据库版本</td>
<td>{$mysql_ver}</td>
</tr>
<tr>
<td>服务器操作系统</td>
<td>{:php_uname('s')}</td>
</tr>
<tr>
<td>WEB运行环境</td>
<td>{:php_sapi_name()}</td>
</tr>
<tr>
<td>上传大小限制</td>
<td>{:ini_get('upload_max_filesize')}</td>
</tr>
<tr>
<td>POST大小限制</td>
<td>{:ini_get('post_max_size')}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="layui-col-md6">
<div class="think-box-shadow">
<table class="layui-table" lay-skin="line" lay-even>
<caption class="text-left margin-bottom-15 font-s14">产品团队</caption>
<colgroup>
<col width="30%">
</colgroup>
<tbody>
<tr>
<td>产品名称</td>
<td>ThinkAdmin</td>
</tr>
<tr>
<td>在线体验</td>
<td><a target="_blank" href="http://demo.thinkadmin.top">http://demo.thinkadmin.top</a></td>
</tr>
<tr>
<td>官方QQ群</td>
<td>
<a href="http://shang.qq.com/wpa/qunwpa?idkey=ae25cf789dafbef62e50a980ffc31242f150bc61a61164458216dd98c411832a">
<img src="//pub.idqqimg.com/wpa/images/group.png" style="height:18px;width:auto" target="_blank">
</a>
</td>
</tr>
<tr>
<td>项目地址</td>
<td><a target="_blank" href="https://github.com/zoujingli/ThinkAdmin">https://github.com/zoujingli/ThinkAdmin</a></td>
</tr>
<tr>
<td>BUG反馈</td>
<td><a target="_blank" href="https://github.com/zoujingli/ThinkAdmin/issues">https://github.com/zoujingli/ThinkAdmin/issues</a></td>
</tr>
<tr>
<td>开发团队</td>
<td><a href="http://www.cuci.cc" target="_blank">广州楚才信息科技有限公司</a></td>
</tr>
<tr>
<td>团队官网</td>
<td><a target="_blank" href="http://www.cuci.cc">http://www.cuci.cc</a></td>
</tr>
<tr>
<td>办公地址</td>
<td>广州市天河区东圃一横路东泷商贸中心G02</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/block}

50
application/admin/view/login/index.html

@ -0,0 +1,50 @@
{extend name="admin@index/index"}
{block name="body"}
<div class="login-container" data-supersized="__ROOT__/static/theme/img/login/bg1.jpg,__ROOT__/static/theme/img/login/bg2.jpg">
<div class="header notselect layui-hide-xs">
<a href="{:url('@')}" class="title">{:sysconf('app_name')}<span class="padding-left-5 font-s10">{:sysconf('app_version')}</span></a>
{notempty name='devMode'}
<a class="pull-right layui-anim layui-anim-fadein" 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">系统管理</h2>
<ul>
<li class="username">
<label>
<i class="layui-icon layui-icon-username"></i>
<input class="layui-input" required pattern="^\S{4,}$" name="username" autofocus autocomplete="off" placeholder="请输入账号">
</label>
</li>
<li class="password">
<label>
<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="请输入密码">
</label>
</li>
<li class="text-center padding-top-20">
<input type="hidden" name="skey" value="{$loginskey|default=''}">
<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">推荐使用谷歌浏览器</a></p>
{:sysconf('site_copy')}
{if sysconf('miitbeian')}<span class="padding-5">|</span><a target="_blank" href="http://www.miitbeian.gov.cn">{:sysconf('miitbeian')}</a>{/if}
</div>
</div>
{/block}
{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='script'}
<script src="__ROOT__/static/plugs/supersized/supersized.3.2.7.min.js"></script>
{/block}

11
application/admin/view/main.html

@ -0,0 +1,11 @@
<div class="layui-card layui-bg-gray">
{block name='style'}{/block}
{notempty name='title'}
<div class="layui-card-header layui-anim layui-anim-fadein notselect">
<span class="layui-icon layui-icon-next font-s10 color-desc margin-right-5"></span>{$title|default=''}
<div class="pull-right">{block name='button'}{/block}</div>
</div>
{/notempty}
<div class="layui-card-body layui-anim layui-anim-upbit">{block name='content'}{/block}</div>
{block name='script'}{/block}
</div>

88
application/admin/view/menu/form.html

@ -0,0 +1,88 @@
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label">上级菜单</label>
<div class="layui-input-block">
<select name='pid' class='layui-select full-width' lay-ignore>
<!--{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>,请填写系统节点(如: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">
<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" 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>,设置菜单选项前置图标,目前只支持 Font Awesome 5.2.0 字体图标</p>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
</form>
{block name='script'}
<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>', 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}'), [])
});
});
</script>
{/block}

80
application/admin/view/menu/index.html

@ -0,0 +1,80 @@
{extend name='main'}
{block name="button"}
{if auth("admin/menu/add")}
<button data-modal='{:url("add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
{/if}
{if auth("admin/menu/remove")}
<button data-action='{:url("remove")}' data-csrf="{:systoken('admin/menu/remove')}" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>删除菜单</button>
{/if}
{/block}
{block name="content"}
<div class="think-bg-white">
{empty name='list'}
<blockquote class="layui-elem-quote">没 有 记 录 哦!</blockquote>
{else}
<table class="layui-table" lay-skin="line">
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<input data-auto-none data-check-target='.list-check-box' type='checkbox'>
</th>
<th class='list-table-sort-td'>
<button type="button" data-reload class="layui-btn layui-btn-xs">刷 新</button>
</th>
<th class='text-center' style="width:30px"></th>
<th style="width:180px"></th>
<th class='layui-hide-xs' style="width:180px"></th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick>
<td class='list-table-check-td think-checkbox'>
<input class="list-check-box" value='{$vo.ids}' type='checkbox'>
</td>
<td class='list-table-sort-td'>
<input data-action-blur="{:request()->url()}" data-value="id#{$vo.id};action#sort;sort#{value}" data-loading="false" value="{$vo.sort}" class="list-sort-input">
</td>
<td class='text-center'><i class="{$vo.icon} font-s18"></i></td>
<td class="nowrap"><span class="color-desc">{$vo.spl|raw}</span>{$vo.title}</td>
<td class='layui-hide-xs'>{$vo.url}</td>
<td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}</td>
<td class='text-center nowrap notselect'>
{if auth("admin/menu/add")}
<span class="text-explode">|</span>
<!--{if $vo.spt < 2}-->
<a class="layui-btn layui-btn-xs layui-btn-primary" data-title="添加子菜单" data-modal='{:url("add")}?pid={$vo.id}'>添 加</a>
<!--{else}-->
<a class="layui-btn layui-btn-xs layui-btn-disabled">添 加</a>
<!--{/if}-->
{/if}
{if auth("admin/menu/edit")}
<a data-dbclick class="layui-btn layui-btn-xs" data-title="编辑菜单" data-modal='{:url("admin/menu/edit")}?id={$vo.id}'>编 辑</a>
{/if}
{if $vo.status eq 1 and auth("admin/menu/forbid")}
<a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('forbid')}" data-value="id#{$vo.ids};status#0" data-csrf="{:systoken('admin/menu/forbid')}">禁 用</a>
{elseif auth("admin/menu/resume")}
<a class="layui-btn layui-btn-warm layui-btn-xs" data-action="{:url('resume')}" data-value="id#{$vo.ids};status#1" data-csrf="{:systoken('admin/menu/resume')}">启 用</a>
{/if}
{if auth("admin/menu/remove")}
<a class="layui-btn layui-btn-danger layui-btn-xs" data-confirm="确定要删除数据吗?" data-action="{:url('remove')}" data-value="id#{$vo.ids}" data-csrf="{:systoken('admin/menu/remove')}">删 除</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{/empty}
</div>
{/block}

67
application/admin/view/oplog/index.html

@ -0,0 +1,67 @@
{extend name='main'}
{block name="button"}
{if auth("admin/oplog/clear")}
<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
{/if}
{if auth("admin/oplog/remove")}
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('admin/oplog/remove')}" 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 class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<input data-auto-none data-check-target='.list-check-box' type='checkbox'>
</th>
<th class='text-left nowrap'>操作账号</th>
<th class='text-left nowrap'>权限节点</th>
<th class='text-left nowrap'>操作行为</th>
<th class='text-left nowrap'>地理位置</th>
<th class='text-left nowrap'>操作时间</th>
<th></th>
</tr>
</thead>
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick>
<td class='list-table-check-td think-checkbox'>
<input class="list-check-box" value='{$vo.id}' type='checkbox'>
</td>
<td class="text-left nowrap">{$vo.username|default='-'}</td>
<td class="text-left nowrap">{$vo.node|default='-'}</td>
<td class='text-left nowrap'>
<p class="color-text">{$vo.action|default='-'}</p>
<p class="color-desc">{$vo.content|default='-'}</p>
</td>
<td class='text-left nowrap'>
<p class="color-text">{$vo.geoip|default='-'}</p>
<p class="color-desc">{$vo.isp|default='-'}</p>
</td>
<td class='text-left nowrap'>
日期:{$vo.create_at|format_datetime|str_replace=' ','<br><span class="color-desc">时间:',###|raw}</span>
</td>
<td class='text-left nowrap'>
{if auth("admin/oplog/remove")}
<a data-dbclick class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该日志吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/oplog/remove')}">删 除</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
{/notempty}
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

56
application/admin/view/oplog/index_search.html

@ -0,0 +1,56 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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="username" value="{$Think.get.username|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="node" value="{$Think.get.node|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="action" value="{$Think.get.action|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="content" value="{$Think.get.content|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="geoip" value="{$Think.get.geoip|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="{$Think.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>
<script>form.render()</script>

79
application/admin/view/queue/index.html

@ -0,0 +1,79 @@
{extend name='main'}
{block name="button"}
{if auth("admin/queue/remove")}
<button data-action='{:url("remove")}' data-confirm="确定要删除这些任务吗?" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>删除任务</button>
{/if}
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='queue/index_search'}
<table class="layui-table margin-top-15" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<input data-auto-none data-check-target='.list-check-box' type='checkbox'>
</th>
<th class='text-left nowrap'>任务信息</th>
<th class='text-left nowrap'>任务时间</th>
<th class='text-left nowrap'>任务状态</th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr>
<td class='list-table-check-td think-checkbox'>
<input class="list-check-box" value='{$vo.id}' type='checkbox'>
</td>
<td class='text-left nowrap'>
任务名称:{$vo.title}
<br>
任务指令:{$vo.uri}
</td>
<td class='text-left nowrap'>
创建时间:{$vo.create_at|format_datetime|raw}
<br>
跟进时间:{$vo.status_at|format_datetime|raw}
</td>
<td class='text-left nowrap'>
任务状态:{eq name='vo.double' value='1'}
<span class="layui-badge layui-bg-green margin-right-5"></span>
{else}
<span class="layui-badge layui-bg-blue margin-right-5"></span>
{/eq}
{eq name='vo.status' value='1'}
<span class="layui-badge layui-bg-black">待处理</span>
{elseif $vo.status eq 2}
<span class="layui-badge layui-bg-green">处理中</span>
{elseif $vo.status eq 3}
<span class="layui-badge layui-bg-blue">处理完成</span>
{elseif $vo.status eq 4}
<span class="layui-badge layui-bg-red margin-right-5">处理失败</span>
<a class="layui-badge layui-bg-green" data-tips-text="重置该任务" data-action="{:url('redo')}" data-value="id#{$vo.id}">
<i class="layui-icon font-s12">&#xe669;</i>
</a>
{/eq}
{if auth("admin/queue/remove") and in_array($vo.status,[1,3,4])}
<a data-action='{:url("remove")}' data-confirm="确定要删除该任务吗?" data-value="id#{$vo.id}" data-tips-text="删除该任务" class='layui-badge layui-bg-red margin-left-5'>
<i class="layui-icon">&#xe640;</i>
</a>
{/if}
<br>
状态描述:<span class="color-desc">{$vo.status_desc|raw|default="没有获取到状态描述"}</span>
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

68
application/admin/view/queue/index_search.html

@ -0,0 +1,68 @@
{if session('admin_user.username') eq 'admin'}
<fieldset class="margin-bottom-10">
<legend>进程守护</legend>
<div class="layui-code border-0 margin-top-0">
<p class="color-desc margin-top-10">当前消息队列守护进程运行状态</p>
{$message|raw|default='--'}
<p class="color-desc margin-top-10">配置定时任务来检查并启动进程(建议每分钟执行)</p>
{$cmd|default='--'}
</div>
</fieldset>
{/if}
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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="{$Think.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">
<select class="layui-select" name="uri" lay-search>
<option value="">-- 全部指令 --</option>
{foreach $uris as $uri}
<!--{eq name='Think.get.uri' value='$uri'}-->
<option selected value="{$uri}">{$uri}</option>
<!--{else}-->
<option value="{$uri}">{$uri}</option>
<!--{/eq}-->
{/foreach}
</select>
</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 $Think.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="{$Think.get.create_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="status_at" value="{$Think.get.status_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>
<script>form.render()</script>

63
application/admin/view/user/form.html

@ -0,0 +1,63 @@
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
<div class="layui-card-body">
<div class="layui-form-item">
<label class="layui-form-label label-required">用户账号</label>
<div class="layui-input-block">
<!--{if isset($vo) and isset($vo.username)}-->
<input disabled value='{$vo.username|default=""}' class="layui-input layui-bg-gray">
<!--{else}-->
<input name="username" value='{$vo.username|default=""}' required pattern="^.{4,}$" placeholder="请输入4位及以上字符用户名称" class="layui-input">
<!--{/if}-->
<p class="color-desc">用户账号创建后,不允许再次修改。</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系手机</label>
<div class="layui-input-block">
<input type="tel" maxlength="11" autocomplete="off" autofocus name="phone" value='{$vo.phone|default=""}' pattern="^1[3-9][0-9]{9}$" placeholder="请输入联系手机" class="layui-input">
<p class="color-desc">可选,用户联系手机号码,需要填写正确的格式</p>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系邮箱</label>
<div class="layui-input-block">
<input name="mail" autocomplete="off" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" value='{$vo.mail|default=""}' placeholder="请输入联系邮箱" class="layui-input">
<p class="color-desc">可选,用户联系电子邮箱,需要填写正确的格式</p>
</div>
</div>
{notempty name='authorizes'}
<div class="layui-form-item">
<label class="layui-form-label">访问授权</label>
<div class="layui-input-block">
{if isset($vo.username) and $vo.username eq 'admin'}
<span class="color-desc" style="line-height:36px">超级用户不需要配置权限</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}
{empty name='authorizes'}<span class="color-desc" style="line-height:36px">未配置权限</span>{/empty}
{/if}
</div>
</div>
{/notempty}
<div class="layui-form-item">
<label class="layui-form-label">用户描述</label>
<div class="layui-input-block">
<textarea placeholder="请输入用户描述" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="layui-form-item text-center">
{notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
<button class="layui-btn" type='submit'>保存数据</button>
<button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
</div>
<script>window.form.render();</script>
</form>

77
application/admin/view/user/index.html

@ -0,0 +1,77 @@
{extend name='main'}
{block name="button"}
{if auth("admin/user/add")}
<button data-modal='{:url("add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
{/if}
{if auth("admin/user/remove")}
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('admin/user/remove')}" data-confirm="确定要删除这些用户吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除用户</button>
{/if}
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='user/index_search'}
<table class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'>
<label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label>
</th>
<th class='text-left nowrap'>用户账号</th>
<th class='text-left nowrap'>联系手机</th>
<th class='text-center nowrap'>登录次数</th>
<th class='text-center nowrap'>使用状态</th>
<th class='text-left nowrap'>创建时间</th>
<th class='text-left nowrap'>登录时间</th>
<th class='text-left nowrap'></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr data-dbclick>
<td class='list-table-check-td think-checkbox'>
<label><input class="list-check-box" value='{$vo.id}' type='checkbox'></label>
</td>
<td class='text-left nowrap'>{$vo.username|default=''}</td>
<td class='text-left nowrap'>{$vo.phone|default='-'}</td>
<td class='text-center nowrap'>{$vo.login_num|default=0}</td>
<td class='text-center nowrap'>{eq name='vo.status' value='0'}<span class="color-red">已禁用</span>{else}<span class="color-green">使用中</span>{/eq}</td>
<td class='text-left nowrap'>{$vo.create_at|format_datetime}</td>
<td class='text-left nowrap'>{if $vo.login_num>0}{$vo.login_at|format_datetime}{else} - {/if}</td>
<td class='text-left nowrap'>
{if auth("admin/user/pass")}
<a class="layui-btn layui-btn-normal layui-btn-sm" data-title="设置密码" data-modal='{:url("pass")}?id={$vo.id}'>密 码</a>
{/if}
{if auth("admin/user/edit")}
<a data-dbclick class="layui-btn layui-btn-sm" data-title="编辑用户" data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
{/if}
{if $vo.status eq 1 and auth("admin/user/forbid")}
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-value="id#{$vo.id};status#0" data-csrf="{:systoken('admin/user/forbid')}">禁 用</a>
{elseif $vo.status eq 0 and auth("admin/user/resume")}
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-value="id#{$vo.id};status#1" data-csrf="{:systoken('admin/user/resume')}">启 用</a>
{/if}
{if auth("admin/user/remove")}
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该用户吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('admin/user/remove')}">删 除</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

57
application/admin/view/user/index_search.html

@ -0,0 +1,57 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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="username" value="{$Think.get.username|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="phone" value="{$Think.get.phone|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="mail" value="{$Think.get.mail|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">
{foreach [''=>'-- 全部状态 --','0'=>'已禁用的账号','1'=>'使用中的账号'] as $k=>$v}
{eq name='Think.get.status' value='$k.""'}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/eq}
{/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="login_at" value="{$Think.get.login_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>
<script>form.render()</script>

53
application/admin/view/user/pass.html

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

2
application/api/common.php

@ -0,0 +1,2 @@
<?php

41
application/api/controller/Base.php

@ -0,0 +1,41 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2018/11/15 9:47
* +----------------------------------------------------------------------
* Des: 前台基类
+----------------------------------------------------------------------*/
namespace app\api\controller;
use think\Controller;
class Base extends Controller
{
/**
* 配置信息
* @var array
*/
static protected $config = [];
public function __construct()
{
parent::__construct();
}
/**
* 获取全局配置信息
* @return \type
*/
private function getConfig()
{
}
}

166
application/api/controller/Sms.php

@ -0,0 +1,166 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2019/04/09 23:50
* +----------------------------------------------------------------------
* Des: 短信发送api
+----------------------------------------------------------------------*/
namespace app\api\controller;
use service\SendSms;
use think\Db;
use think\facade\Cache;
use think\facade\Validate;
class Sms extends Base
{
/**
* @var string
* 短信服务商数据表
*/
private static $table = 'cloud_sms';
/**
* @var string
* 短信日志表
*/
private static $table_log = 'cloud_sms_log';
/**
* @var string
* 短信服务商模板配置表
*/
private static $table_config = 'cloud_sms_config';
public static function db($table = '')
{
//读取短信配置信息
$table = !empty($table) ? $table : self::$table;
$sms = Db::name($table)->where('status=1')->select();
if (empty($sms)) {
return json_status(40602);
}
//随机一个数组元素
$key = array_rand($sms);
$sms = $sms[$key];
return empty($sms) ? json_status(40601) : $sms;
}
/**
* 发送短信验证码【单条】
* @param string $mobile 手机号
* @param int $tempid 模板id
* @return \type|void
*/
public static function send($mobile = '', $tempid = 1)
{
if (!Validate::is($mobile, 'mobile')) {
return json_status(40601);
}
//获取短信服务端信息
$sms = self::db();
//替换模板变量
$code = mt_rand(999, 10000);
$replace_str = [
'{code}' => $code,
];
Cache::set('sms_' . $mobile . '_' . $tempid, $code, 300);
$text = self::parseTemplate($tempid, $replace_str);
$data = SendSms::send($sms, $mobile, $sms['code_url'], $text);
$data['mobile'] = $mobile; //重复发送的api没有返回mobile
self::writeLog($data, $sms['name'], $text); //记录短信日志
return $data;
}
/**
* 验证验证码
* @param $mobile 手机号
* @param $code 验证码
* @param $tempid 模板id
*/
public static function verification($mobile, $code, $tempid = 1)
{
$validate = new \app\api\validate\Sms;
$data = [
'mobile' => $mobile,
'code' => $code,
];
if (!$validate->check($data)) {
return json_status($validate->getError());
}
//验证手机号
$cache_name = 'sms_' . $mobile . '_' . $tempid;
$cache_code = Cache::get($cache_name);
if ($cache_code != $code) {
return json_status(40605);
}
//删除成功后的缓存
Cache::rm($cache_name);
return json_status();
}
/**
* 发送系统通知类【单条】
* @param string $mobile 手机号
* @param int $tempid 模板id
* @param int $arr 需要替换的变量数组
* @return \type|void
*/
public static function sendNotify($mobile = 0, $arr = [], $tempid = 3)
{
if (!Validate::is($mobile, 'mobile')) {
return json_status(40601);
}
//获取短信服务端信息
$sms = self::db();
$text = self::parseTemplate($tempid, $arr);
$data = SendSms::send($sms, $mobile, $sms['notify_url'], $text);
self::writeLog($data, $sms['name'], $text); //记录短信日志
return $data;
}
/**
* 记录发送日志
* @param array $arr 短信服务商返回数据
* @param $sms_name 当前短信发送服务商名称
* @param $text 短信内容
*/
private static function writeLog($arr = [], $sms_name, $text)
{
if (isset($arr['data'][0])) {
$_data = $arr['data'][0];
} else {
$_data = $arr;
}
$_data['text'] = $text;
$_data['platform'] = $sms_name;
$_data['status'] = $_data['code'] === 0 ? 1 : 0;
$_data['create_time'] = time();
$_data['month'] = date('Y-m');
Db::name(self::$table_log)->strict(false)->insert($_data);
}
/**
* 短信模板解析
* @param $tempid
* @param array $arr
*/
private static function parseTemplate($tempid, $arr = [])
{
$template = Db::name(self::$table_config)->find($tempid);
if (empty($template)) {
return json_status(40603);
}
$template['content'] = str_replace(array_keys($arr), $arr, $template['content']);
return $template['content'];
}
}

33
application/api/validate/Sms.php

@ -0,0 +1,33 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2018/11/30 9:47
* +----------------------------------------------------------------------
* Des: 短信验证
+----------------------------------------------------------------------*/
namespace app\api\validate;
use think\Validate;
class Sms extends Validate
{
protected $rule = [
'mobile' => 'require|length:11',
'code' => 'require|length:4',
];
protected $message = [
'mobile.require' => '40601',
'mobile.length' => '40601',
'code.require' => '40604',
'code.length' => '40604',
];
}

122
application/index/common.php

@ -0,0 +1,122 @@
<?php
/**
* 计算指定时间与当前比较剩余多少天
* @param $time
*/
function time_days($time = 0)
{
if (!$time || !is_numeric($time)) {
return ['msg' => '未出租', 'num' => 2];
}
$now_time = time();
$days = ceil(($time - $now_time) / 3600 / 24);
if ($days > 0) {
return ['msg' => $days . '天后到期', 'num' => 2];
} else {
return ['msg' => '已过期' . abs($days) . '天', 'num' => 1];
}
}
/**
* 格式化数组,删除字段
* @param type $_arr 数组对象
* @param type $field 需要删除的字段
*/
function format_field(&$_arr = array(), $_field = array())
{
if (!$_arr || !$_field) {
return;
}
if (!is_array($_field)) {
$_field = explode(',', $_field);
}
$_field = array_flip($_field);
array_walk($_arr, function (&$v, &$k) use ($_field) {
$v = array_intersect_key($v, $_field);
});
}
/**
*
* @param type $code 状态编码
* @param type $data 返回数据
* @param type $msg 错误的提示信息
* @return type
*/
function send_http_status($code, $_data = array(), $msg = '')
{
if (!$code) {
return;
}
$_status = config('status');
if (isset($_status[$code])) {
header('HTTP/1.1 200 ' . $_status[$code]);
// 确保FastCGI模式下正常
header('Status: 200 ' . $_status[$code]);
}
if ($_data == null) {
$_data = [];
}
$msg = empty($msg) ? $_status[$code] : $msg;
$_msg = [
'code' => $code,
'msg' => $msg,
'data' => $_data,
'time' => $_SERVER['REQUEST_TIME'],
];
return json_encode($_msg, JSON_UNESCAPED_UNICODE);
}
/**
* 去除html js css 危险注入代码
*/
function filter_danger_str($_string)
{
$search = array("'<script[^>]*?>.*?</script>'si", // 去掉 javascript
"'<style[^>]*?>.*?</style>'si", // 去掉 css
"'<[/!]*?[^<>]*?>'si", // 去掉 HTML 标记
"'<!--[/!]*?[^<>]*?>'si", // 去掉 注释标记
"'([rn])[s]+'", // 去掉空白字符
"'&(quot|#34);'i", // 替换 HTML 实体
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i",
);
$replace = array("", "", "", "", "\1", "\"", "&", "<", ">", " ", chr(161), chr(162), chr(163), chr(169));
$out = preg_replace($search, $replace, $_string);
return htmlspecialchars_custom($out);
}
//过滤单双引号
function htmlspecialchars_custom($str)
{
return htmlspecialchars($str, ENT_QUOTES);
}
function order_no(){
return date('Ymd').rand(1000,9999).date('His').rand(1000,9999);
}
function formart_time($time){
if ($time < strtotime(date("Y-m-d",strtotime('+1 day'))) ){
return '今天';
}elseif ( $time < strtotime(date("Y-m-d",strtotime('+2 day'))) ){
return '明天';
}else{
return date('Y-m-d',$time);
}
}

42
application/index/controller/Ad.php

@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class Ad extends Base
{
public $table = 'CloudAdData';
/**
* 获取广告列表
*/
public function index()
{
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 3);
$data = Db::name($this->table)->where('is_delete', 0)->page($page, $pagesize)->order('sort ASC')->select();
return json($data);
}
}

212
application/index/controller/Base.php

@ -0,0 +1,212 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Controller;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class Base extends Controller
{
protected static $table_user = "CloudMember";
public $table_room_crontab = 'CloudRoomCrontab';//房间时间切割
public function __construct(App $app = null)
{
parent::__construct($app);
//判断是否开启验证
if (config('istoken')) {
$this->run(); //token验证
}
}
/**
* 用户信息传递
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
protected static function auth()
{
//$this->info(); //获取相关信息
if (!isset($_SERVER['HTTP_USERID'])) {
exit(send_http_status(412));
}
$user_id = $_SERVER['HTTP_USERID'];
$_USER = Db::name(self::$table_user)->where('id', $user_id)->find();
if (!$_USER) {
exit(send_http_status(415));
}
!defined('USER_ID') ? define('USER_ID', $_USER['id']) : '';
!defined('MEMBER') ? define('MEMBER', $_USER) : '';
}
/**
* 会员发布权限判断
* @param int $curr_count 当前已有数据统计
* @param string $count_type 判断的类型 默认房源,否则根据传入的类型
*/
protected static function authAddHouse($curr_count = 0, $count_type = 'count')
{
//子账号不允许删除和添加
if ($_SERVER['HTTP_SUBUSERID'] > 0) {
exit(send_http_status(417));
}
//判断有没有手机号
if (empty(MEMBER['phone']) || strlen(MEMBER['phone']) != 11) {
exit(send_http_status(51016));
}
//暂时免费
return;
//超级管理员直接返回
if (MEMBER['is_manager'] == 1) {
return;
}
//判断当前用户 会员是否过期(普通用户不用判断)
if (MEMBER['vip_level'] > 0 && MEMBER['vip_endtime'] < time() && MEMBER['is_manager'] != 1) {
exit(send_http_status(416));
}
//获取等级配置信息
$vip_level = config('vip_level');
$member_vip = $vip_level[MEMBER['vip_level']];
if ($curr_count >= $member_vip[$count_type]) {
exit(send_http_status(51004));
}
}
/**
* 获取常用硬件信息
*/
protected function info()
{
$code = '';
if (!isset($_SERVER['HTTP_DEVICENAME'])) {
$code = 408;
}
if (!isset($_SERVER['HTTP_SYSTEMVERSION'])) {
$code = 409;
}
if (!isset($_SERVER['HTTP_DEVICECODE'])) {
$code = 410;
}
if (!isset($_SERVER['HTTP_PHONETYPE'])) {
$code = 411;
}
if (!isset($_SERVER['HTTP_USERID'])) {
$code = 412;
}
if ($code) {
exit(send_http_status($code));
}
//获取、设备号、机型、终端
$devicename = 'Android';
if (strtolower($_SERVER['HTTP_DEVICENAME']) != strtolower($devicename)) {
$devicename = 'iOS';
}
//获取版本号
$version = isset($_SERVER['HTTP_VERSION']) ? $_SERVER['HTTP_VERSION'] : 0;
defined('VERSION') or define("VERSION", $version); //版本号
defined('DEVICENAME') or define("DEVICENAME", $devicename); //终端名称
defined('SYSTEMVERSION') or define("SYSTEMVERSION", strtoupper($_SERVER['HTTP_SYSTEMVERSION'])); //系统版本
defined('DEVICECODE') or define("DEVICECODE", $_SERVER['HTTP_DEVICECODE']); //设备号
defined('PHONETYPE') or define("PHONETYPE", $_SERVER['HTTP_PHONETYPE']); //机型
defined('USERID') or define("USERID", $_SERVER['HTTP_USERID']);
}
/**
* 根据密钥、标识、时间戳、随机数 验证请求接口
*/
public function run()
{
//客户端标识列表
$_client = config('CLIENT');
$_secret = config('SECRET');
$code = '';
//没有指定平台标识
defined('CLIENT') or define("CLIENT", strtoupper($_SERVER['HTTP_CLIENT'])); //终端名称
if (empty(CLIENT) || !in_array(CLIENT, $_client)) {
$code = 201;
}
//判断标识是否正确
if (!isset($_SERVER['HTTP_APPID']) || $_SERVER['HTTP_APPID'] != $_secret[CLIENT]['APPID']) {
$code = 202;
}
//指定随机数
$nonce = $_SERVER['HTTP_NONCE'];
if (!isset($nonce) || empty($nonce)) {
$code = 203;
}
//判断加密串
$openkey = $_secret[CLIENT]['APPID'] . $nonce . $_secret[CLIENT]['SECRET'];
$encry_old = md5($openkey);
$encry = md5($openkey . $_SERVER['HTTP_USERID']);
if ($_SERVER['HTTP_OPENKEY'] != $encry && $encry_old != $_SERVER['HTTP_OPENKEY']) {
$code = 207;
}
if ($code) {
exit(send_http_status($code));
}
}
/**
* 根据收租方式 切割提醒的时间节点
* @param $_data 房间数据
* @param int $month 指定分割月数
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
protected function crontab_room($_data, $month = 3)
{
$start_time = $_data['start_time'];
$end_time = $_data['end_time'];
//计算指定天数后的时间戳
$_arr = [];
while ($start_time < $end_time) {
$arr_temp['room_id'] = $_data['id'];
$arr_temp['user_id'] = USER_ID;
$arr_temp['start_time'] = $start_time;
$arr_temp['end_time'] = $start_time = strtotime('+' . $month . ' month', $start_time);
$arr_temp['create_time'] = time();
$_arr[] = $arr_temp;
}
//删除最后一个元素,置换为end_time(防止开始时间与结束时间不一致)
$last_arr = array_pop($_arr);
$last_arr['end_time'] = $end_time;
$_arr[] = $last_arr;
//新增前先清空
$house_crontab = Db::name($this->table_room_crontab);
$house_crontab->where('room_id', $_data['id'])->where('user_id', USER_ID)->delete();
$house_crontab->insertAll($_arr);
}
}

269
application/index/controller/Clean.php

@ -0,0 +1,269 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\Db;
/**
* 保洁
* Class Index
* @package app\index\controller
*/
class Clean extends Base
{
public $table = 'CloudClean';
public function __construct()
{
parent::__construct();
parent::auth();
}
/**
* 获取列表
*/
public function index()
{
$data = Db::name($this->table)->select();
return send_http_status(200, $data);
}
/**
* 更改打扫时间
*/
public function change_date()
{
$param = $this->request->param();
$res = Db::name('CloudCleanState')
->where('id', $param['id'])
->update([
'create_time' => strtotime($param['date']),
]);
return send_http_status(200, ['date' => formart_time(strtotime($param['date']))]);
}
/**
* 我要打扫的房间
*/
public function my_clean()
{
$param = $this->request->param();
$is_complete = $this->request->param('is_complete', 0);
$type = $is_complete == 0 ? '=' : '>';
$res = Db::name('CloudCleanState')
->alias('s')
->leftJoin('cloud_clean_order o', 'o.order_no=s.order_no')
->leftJoin('cloud_house h', 'h.id=o.house_id')
->leftJoin('cloud_member m', 'o.openid = m.openid')
->page($param['page'], 10)
->where('o.service_openid', $param['openid'])
->where('s.complete_time', $type, $is_complete)
->field('m.phone,s.id,s.picture,s.create_time,s.complete_time,s.step,s.order_no, h.name,h.photo,h.latitude,h.longitude,h.door_number,o.content,o.second,o.service_openid,m.nickname,m.headimg')
->order('s.create_time', 'ASC')
->select();
foreach ($res as &$v) {
$v['picture'] = json_decode($v['picture'], true);
$v['create_time'] = formart_time($v['create_time']);
$v['complete_time'] = !empty($v['complete_time']) ? date('Y-m-d', $v['complete_time']) : 0;
$v['photo'] = $v['photo'] ? explode(',', $v['photo'])[0] : '';
}
return send_http_status(200, $res);
}
/**
* 我发布的保洁
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function my()
{
$param = $this->request->param();
//$user = Db::name('CloudMember')->where('openid',$param['openid'])->find();
$page = $this->request->param('page', 1);
$query = Db::name('CloudCleanOrder')
->alias('o')
->leftJoin('cloud_house h', 'o.house_id = h.id')
->leftJoin('cloud_member m', 'h.user_id = m.id') // 查询房源手机号
->where('o.state', 1)
->field('m.phone,h.name,h.latitude,h.longitude,h.photo,h.door_number,o.create_time,o.content,o.second,o.complete,o.order_no,o.service_openid')
->order('o.create_time', 'desc')
->limit(($page - 1) * 15, 15);
/*if ($user['is_clean']){
$query->where('o.openid|o.service_openid','=', $param['openid'])->whereNotNull('service_openid');
}else{
$query->where('o.openid',$param['openid']);
}*/
$query->where('o.openid', $param['openid']);
$res = $query->select();
foreach ($res as &$v) {
$v['create_time'] = !empty($v['create_time']) ? date('Y-m-d H:i:s', $v['create_time']) : 0;
$v['photo'] = $v['photo'] ? explode(',', $v['photo'])[0] : '';
}
return send_http_status(200, $res);
}
/**
* 订单详情
*/
public function info()
{
$order_no = $this->request->param('order_no');
$res = Db::name('CloudCleanState')
->alias('s')
->leftJoin('cloud_clean_order o', 'o.order_no=s.order_no')
->leftJoin('cloud_house h', 'h.id=o.house_id')
->leftJoin('cloud_member m', 'o.openid = m.openid')
->where('s.order_no', $order_no)
->field('s.id,s.picture,s.commont,s.commont_time,s.create_time,s.complete_time,s.step,s.order_no, h.name,o.content,o.second,o.service_openid,m.nickname,m.headimg')
->select();
foreach ($res as &$v) {
$v['picture'] = json_decode($v['picture'], true);
$v['create_time'] = formart_time($v['create_time']);
$v['commont'] = [
'nickname' => $v['nickname'],
'headimg' => $v['headimg'],
'commont' => $v['commont'],
'commont_time' => date('Y-m-d H:i:s', $v['commont_time'])
];
$v['complete_time'] = !empty($v['complete_time']) ? date('Y-m-d', $v['complete_time']) : '未打扫';
unset($v['nickname'], $v['headimg'], $v['commont_time']);
}
return send_http_status(200, $res);
}
/**
* 评价
*/
public function commont()
{
$param = $this->request->param();
$res = Db::name('CloudCleanState')->where('id', $param['id'])
->update([
'commont' => $param['commont'],
'commont_time' => time(),
]);
if ($res) {
$data = Db::name('CloudCleanState')
->alias('a')
->leftJoin('cloud_clean_order o', 'o.order_no = a.order_no')
->leftJoin('cloud_member m', 'o.openid = m.openid')
->field('a.commont,a.commont_time,m.nickname,m.headimg')
->where('a.id', $param['id'])
->find();
$data['index'] = $param['index'];
$data['commont_time'] = date('Y-m-d H:i:s', $data['commont_time']);
return send_http_status(200, $data);
} else {
return send_http_status(201, '', '操作失败!');
}
}
/**
* 保洁完成上传图片
* @return \type
*/
public function complete()
{
$param = $this->request->param();
Db::startTrans();
try {
Db::name('CloudCleanState')->where('id', $param['id'])->update([
'service_openid' => $param['openid'],
'picture' => json_encode(explode(',', $param['images'])),
'complete_time' => strtotime($param['complete_time']),
]);
Db::name('CloudCleanOrder')
->where('order_no', $param['order_no'])
->update(['complete' => Db::raw('complete+1')]);
Db::commit();
return send_http_status(200);
} catch (\Exception $e) {
Db::rollback();
return send_http_status(201, '', $e->getMessage());
}
}
public function create()
{
$param = $this->request->post();
$clean = Db::name($this->table)->find($param['cleanid']);
if (!$clean) return $this->error('选项不存在');
$order_no = order_no();
$order = [
'order_no' => $order_no,
'openid' => $param['openid'],
'content' => $clean['title'] . ' - ' . $clean['summary'],
'second' => $clean['second'],
'price' => $clean['price'],
'house_id' => $param['house_id'],
'create_time' => time(),
'update_time' => time(),
];
//生成副表订单
Db::startTrans();
try {
Db::name('CloudCleanOrder')->insert($order);
$row = [];
$day_num = 10;
if ($clean['second'] == 2) {
$day_num = 15;
}
for ($i = 0; $i < $clean['second']; $i++) {
$create_time = strtotime((($i * $day_num) + 1) . ' day');
$row[] = [
'create_time' => $create_time,
'update_time' => $create_time,
'order_no' => $order_no,
'step' => $i + 1
];
}
Db::name('CloudCleanState')->insertAll($row);
Db::commit();
} catch (\Throwable $e) {
Db::rollback();
return send_http_status(202, '', $e->getMessage());
}
$wechat = new \WeChat\Pay(config('wechat.miniapp'));
$options = [
'body' => '保洁' . $clean['title'] . '(' . $clean['second'] . '次)',
'out_trade_no' => $order_no,
'total_fee' => $clean['price'] * 100,
'openid' => $param['openid'],
'trade_type' => 'JSAPI',
'notify_url' => $this->request->domain() . '/index/notify/clean',
'spbill_create_ip' => $this->request->ip(),
];
try {
// 生成预支付码
$result = $wechat->createOrder($options);
// 创建JSAPI参数签名
$options = $wechat->createParamsForJsApi($result['prepay_id']);
// @todo 把 $options 传到前端用js发起支付就可以了
return send_http_status(200, $options);
} catch (Exception $e) {
// 出错啦,处理下吧
return send_http_status(201, '', $e->getMessage());
}
}
}

73
application/index/controller/Collection.php

@ -0,0 +1,73 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 采集数据
* Class Index
* @package app\index\controller
*/
class Collection extends Base
{
private $table = 'CloudHouseCollection';
/**
* 获取问题列表
*/
public function index()
{
$count = Db::name($this->table)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return $_data;
}
/**
* 问题详情
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data = Db::name($this->table)->find($id);
return send_http_status(200, $_data);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
// !empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
});
}
}

46
application/index/controller/Config.php

@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
/**
* 配置信息
* Class Index
* @package app\index\controller
*/
class Config extends Base
{
/**
* 获取配置信息
* @param string $name 配置key名称,支持逗号分割
* @return \type
*/
public function index($name = '')
{
if (!$name) {
return send_http_status(51005);
}
$name = explode(',', $name);
foreach ($name as $v) {
$_data[$v] = config($v);
}
if (is_array($_data)) {
return send_http_status(200, $_data);
}
return send_http_status(413);
}
}

105
application/index/controller/Contract.php

@ -0,0 +1,105 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 合同管理
* Class Index
* @package app\index\controller
*/
class Contract extends Base
{
private $table = 'CloudHouseContract';
public function __construct(App $app = null)
{
parent::__construct($app);
parent::auth();
}
/**
* 获取合同列表
*/
public function index()
{
$_where = 'user_id = ' . USER_ID . ' AND is_del = 0';
$count = Db::name($this->table)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 合同详情
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data = Db::name($this->table)->where('user_id', USER_ID)->find($id);
if ($_data) {
$_data['create_time'] = date('Y-m-d', $_data['create_time']);
$_data['contract_starttime'] = date('Y-m-d', $_data['contract_starttime']);
$_data['contract_endtime'] = date('Y-m-d', $_data['contract_endtime']);
return send_http_status(200, $_data);
}
}
/**
* 删除合同信息
* @param string $id 合同id
* @return \type
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function del($id = '')
{
if ((!$id || !is_numeric($id))) {
return send_http_status(51003);
}
$affected = Db::name($this->table)->where('id', $id)->where('user_id', USER_ID)->update(['is_del' => 1]);
if ($affected) {
return send_http_status(200);
}
return send_http_status(413);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
!empty($v['update_time']) ? $v['update_time'] = date('Y-m-d', $v['update_time']) : $v['update_time'] = '';
});
}
}

137
application/index/controller/Crontab.php

@ -0,0 +1,137 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2018/11/15 9:47
* +----------------------------------------------------------------------
* Des: 短信插件
+----------------------------------------------------------------------*/
namespace app\index\controller;
use think\Controller;
use think\Db;
class Crontab extends Controller
{
/**
* 房间表
* @var string
*/
private $table_room = 'CloudHouseRoom';
/**
* 一手房源时间节点副表
* @var string
*/
private $table_house_crontab = 'CloudHouseCrontab';
/**
* 租户表
* @var string
*/
private $table_tenant = 'CloudHouseTenant';
/**
* 短信日志表
* @var string
*/
private $table_sms_log = 'CloudSmsLog';
/**
* html5支付页面
* @var string
*/
private $url = 'http://xunxibaoapi.yaoyz.com/index/pay/index';
/**
* 到期子房源提醒
* @param int $day 默认3天
*/
public function index($day = 30)
{
if ($day && is_numeric($day)) {
//计算指定天数后的时间戳
$day_time = strtotime('+' . $day . ' day');
$_where[] = ['r.end_time', '<', $day_time]; //结束时间小于当前时间+30天
$_where[] = ['r.end_time', '>', time()]; //且结束时间大于当前时间
$_where[] = ['r.end_time', '<>', ''];
}
$_where[] = ['r.is_del', '=', 0];
$_data = Db::name($this->table_room)->alias('r')->leftJoin('cloud_house_tenant t', 'r.id = t.room_id')->where($_where)->field('r.*,t.phone,t.name')->select();
$this->send($_data);
}
/**
* 到期一手房源提醒
* @param int $day 默认3天
*/
public function house($day = 3)
{
if ($day && is_numeric($day)) {
//计算指定天数后的时间戳
$day_time = strtotime('+' . $day . ' day');
$_where[] = ['create_time', '<', $day_time]; //结束时间小于当前时间+30天
$_where[] = ['create_time', '>', time()]; //且结束时间大于当前时间
$_where[] = ['create_time', '<>', ''];
}
$_data = Db::name($this->table_house_crontab)->where($_where)->select();
$this->sendHouse($_data);
}
/**
* 执行短信发送
* @param $_arr
*
*/
private function send($_arr)
{
if (empty($_arr)) {
return;
}
$curr_month = date('Y-m');
$_sms = new \app\api\controller\Sms();
foreach ($_arr as $k => $v) {
$_str = [
'{url}' => $this->url . '?roomid=' . $v['id'] . '&phone=' . $v['phone'] . '&name=' . $v['name']
];
//判断本月是否发送过,已发送不再发送
$_data = Db::name($this->table_sms_log)->where('mobile', $v['phone'])->where('month', $curr_month)->find();
if (empty($_data)) {
$_sms::sendNotify($v['phone'], $_str, 23);
}
}
}
/**
* 执行短信发送
* @param $_arr
*
*/
private function sendHouse($_arr)
{
if (empty($_arr)) {
return;
}
$curr_month = date('Y-m');
$_sms = new \app\api\controller\Sms();
foreach ($_arr as $k => $v) {
$_str = [
'{address}' => $v['address'] . $v['house_name'] . $v['door_number']
];
//判断本月是否发送过,已发送不再发送
$_data = Db::name($this->table_sms_log)->whereLike('text', '%' . $v["house_name"] . '%')->where('mobile', $v['phone'])->where('month', $curr_month)->find();
if (empty($_data)) {
$_sms::sendNotify($v['phone'], $_str, 24);
}
}
}
}

580
application/index/controller/House.php

@ -0,0 +1,580 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class House extends Base
{
public $table = 'CloudHouse';//房源表
public $table_room = 'CloudHouseRoom';//子房间表
public $table_tenant = 'CloudHouseTenant';//租户表
public $table_holder = 'CloudHouseHolder';//一房东表
public $table_house_crontab = 'CloudHouseCrontab';//一房源定时提醒表
public $table_order_room = 'CloudOrderRoom';//房间续租订单表
public function __construct()
{
parent::__construct();
parent::auth();
}
/**
* 获取管理房源列表
*/
public function index()
{
$_where['is_del'] = 0;
$_where['user_id'] = USER_ID;
$count = Db::name($this->table)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**房源到期列表
* @param int $day 是否只返回过期房源数量,false只返回 ,默认true
* @param bool $is_day
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function expire($day = 3, $is_day = true)
{
if ($day) {
//计算指定天数后的时间戳
$day_time = strtotime('+' . $day . ' day');
$_where[] = ['c.create_time', '<', $day_time]; //结束时间小于当前时间+3天
$_where[] = ['c.create_time', '>', time()]; //且结束时间大于当前时间
$_where[] = ['c.create_time', '<>', ''];
}
$_where[] = ['c.user_id', '=', USER_ID];
$db = Db::name($this->table);
$db->alias('h')->join(['cloud_house_crontab' => 'c'], 'h.id = c.house_id');
$db->where($_where)->where('h.is_del', 0);
$db->field('h.*,c.create_time AS expire_time');
$_result = $db->order('h.id', "DESC")->select();
if (!$is_day) {
return count($_result);
}
if (empty(count($_result))) {
return send_http_status(200, []);
}
self::formatRoomData($_result);
$_data['list'] = $_result;
$_data['pages'] = 1;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 获取子房间列表
* @param int $day 即将到期参数 不传默认
* @param int $is_is_day 是否只返回过期房源数量,false只返回 ,默认true
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function room($day = 0, $is_day = true)
{
if ($day && is_numeric($day)) {
//计算指定天数后的时间戳
$day_time = strtotime('+' . $day . ' day');
$_where[] = ['r.end_time', '<', $day_time]; //结束时间小于当前时间+30天
// $_where[] = ['end_time', '>', time()]; //且结束时间大于当前时间
$_where[] = ['r.end_time', '<>', ''];
}
$_where[] = ['r.user_id', '=', USER_ID];
$_where[] = ['r.is_del', '=', 0];
$count = Db::name($this->table_room)->alias('r')->where($_where)->count();
if (!$is_day) {
return $count;
}
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table_room)->alias('r')->leftJoin('cloud_house h', 'r.house_id = h.id')->where($_where)->page($page, $pagesize)->order('r.id', "DESC")->field('r.*,h.name,h.photo,h.province,h.city,h.area,h.door_number')->select();
self::formatRoomData($_result);
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**房间到期列表
* @param int $day 是否只返回过期房源数量,false只返回 ,默认true
* @param bool $is_day
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function expire_room($day = 3, $is_day = true)
{
if ($day) {
//计算指定天数后的时间戳
$day_time = strtotime('+' . $day . ' day');
$_where[] = ['c.end_time', '<', $day_time]; //结束时间小于当前时间+3天
// $_where[] = ['c.end_time', '>', time()]; //且结束时间大于当前时间
$_where[] = ['c.end_time', '<>', ''];
$_where[] = ['c.status', '=', 0];
$_where[] = ['c.is_del', '=', 0];
}
$_where[] = ['c.user_id', '=', USER_ID];
// $room_id = Db::name($this->table_room_crontab)->where($_where)->field('room_id')->select();
$db = Db::name($this->table_room);
$db->alias('r')->leftJoin(['cloud_house' => 'h'], 'r.house_id = h.id')->join(['cloud_order_room' => 'c'], 'r.id = c.room_id');
$db->where($_where)->where('r.is_del', 0);
$db->field('r.*,h.name,h.photo,h.province,h.city,h.area,h.door_number,c.end_time AS expire_time,c.start_time AS order_time');
$_result = $db->order('r.id', "DESC")->select();
if (!$is_day) {
return count($_result);
}
self::formatRoomData($_result);
$_data['list'] = $_result;
$_data['pages'] = 1;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 房源详情
* @param string $id 房源id
* @return \type|void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data['house'] = Db::name($this->table)->find($id);
if ($_data['house']) {
//查询户主信息
$_data['holder'] = Db::name($this->table_holder)->find($_data['house']['holder_id']);
//查询子房源列表
$_data['room_list'] = Db::name($this->table_room)->where('is_del', 0)->where('house_id', $id)->order('id', "DESC")->select();
//统计房间支付数据
$_order = new Order();
$_data['house']['orderAmount'] = $_order->orderAmount('', $id);
self::formatRoomData($_data['room_list']);
}
self::formatViewData($_data['house']);
return send_http_status(200, $_data);
}
/**
* 子房间详情
*/
public function viewRoom($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data['room'] = Db::name($this->table_room)->find($id);
if (!empty($_data['room'])) {
//查询租户列表
$_where['room_id'] = $_data['room']['id'];
$_where['is_del'] = 0;
$_data['tenant_list'] = Db::name($this->table_tenant)->where($_where)->order('create_time DESC')->select();
//统计房间支付数据
$_order = new Order();
$_data['room']['orderAmount'] = $_order->orderAmount($_data['room']['id']);
self::formatData($_data['tenant_list']);
}
self::formatViewData($_data['room']);
return send_http_status(200, $_data);
}
/**
* 租户详情
*/
public function viewTenant($id = '')
{
if (!$id) {
return;
}
//获取租户详情
$_data['tenant'] = Db::name($this->table_tenant)->find($id);
if (empty($_data['tenant'])) {
return;
}
$_data['tenant']['sex_id'] = $_data['tenant']['sex'];
$_data['tenant']['sex'] = config('sex')[$_data['tenant']['sex']];
if (!empty($_data['tenant'])) {
//查询交租记录
$_where['room_id'] = $_data['tenant']['id'];
$_data['tenant_list'] = Db::name($this->table_tenant)->where($_where)->select();
}
return send_http_status(200, $_data);
}
/**
* 添加一手房源数据及一手房东信息
*/
public function add()
{
$_data = $this->request->post();
$_data['create_time'] = $_data['update_time'] = time();
$_data['start_time'] = !empty($_data['start_time']) ? strtotime($_data['start_time']) : '';
$_data['end_time'] = !empty($_data['end_time']) ? strtotime($_data['end_time']) : '';
if ($_data['start_time'] >= $_data['end_time']) {
return send_http_status(51000);
}
//会员等级权限判断
$count = Db::name($this->table)->where('user_id', USER_ID)->count();
self::authAddHouse($count);
$_data['user_id'] = USER_ID;
$_data = array_filter($_data);
//添加一房东信息
$holder_id = Db::name($this->table_holder)->strict(false)->insertGetId($_data);
if ($holder_id) {
//添加房源数据
$_data['holder_id'] = $holder_id;
$id = Db::name($this->table)->strict(false)->insertGetId($_data);
if ($id) {
//定时任务短信提醒房租到期数据更新
$_data['id'] = $id; //添加成功后的房源id
$this->crontab($_data);
return send_http_status(200);
}
}
return send_http_status(413);
}
/**
* 修改一手房源数据及一手房东信息
*/
public function edit()
{
$_data = $this->request->post();
$_data['update_time'] = time();
$_data['user_id'] = USER_ID;
$_data['start_time'] = !empty($_data['start_time']) ? strtotime($_data['start_time']) : '';
$_data['end_time'] = !empty($_data['end_time']) ? strtotime($_data['end_time']) : '';
if ($_data['start_time'] >= $_data['end_time']) {
return send_http_status(51000);
}
//修改房源数据
$affected = Db::name($this->table)->strict(false)->update($_data);
$_data = array_filter($_data);
if ($affected) {
//定时任务短信提醒房租到期数据更新
$this->crontab($_data);
//修改一房东信息
unset($_data['id']);
Db::name($this->table_holder)->where('id', $_data['holder_id'])->strict(false)->update($_data);
}
if ($affected) {
return send_http_status(200);
}
return send_http_status(413);
}
/**
* 添加子房间
*/
public function addRoom()
{
//会员等级权限判断
$count = Db::name($this->table_room)->where('user_id', USER_ID)->count();
self::authAddHouse($count, 'count_room');
$_data = $this->request->post();
$_data['create_time'] = $_data['update_time'] = time();
$_data['user_id'] = USER_ID;
$_data = array_filter($_data);
$id = Db::name($this->table_room)->strict(false)->insertGetId($_data);
if (!$id) {
return send_http_status(51002);
}
return send_http_status(200);
}
/**
* 修改子房间
*/
public function editRoom()
{
self::authAddHouse(0, 'count_room');
$_data = $this->request->post();
//是否上架到首页共享房源,即清空时间节点
if ($_data['is_up'] == 'true') {
$_data['start_time'] = $_data['end_time'] = time() - 10000;
} else {
$_data['start_time'] = !empty($_data['start_time']) ? strtotime($_data['start_time']) : '';
$_data['end_time'] = !empty($_data['end_time']) ? strtotime($_data['end_time']) : '';
if ($_data['start_time'] > $_data['end_time']) {
return send_http_status(51000);
}
}
$_data['update_time'] = time();
$_data['user_id'] = USER_ID;
unset($_data['house_id']);
$refected = Db::name($this->table_room)->strict(false)->update($_data);
if (!$refected) {
return send_http_status(51002);
}
//根据用户指定收费方式 切割时间
$_data['id'] = $_data['id']; //添加成功后的房间id
$this->crontab_room($_data, $_data['rent_type']);
return send_http_status(200);
}
/**
* 添加租户
*/
public function addTenant()
{
$_data = $this->request->post();
$where_tenant['room_id'] = $_data['room_id'];
$where_tenant['card_id'] = $_data['card_id'];
$_tenant = Db::name($this->table_tenant)->where($where_tenant)->find();
if ($_tenant) {
return send_http_status(51001);
}
$_data['start_time'] = $house_data['start_time'] = !empty($_data['start_time']) ? strtotime($_data['start_time']) : '';
$_data['end_time'] = $house_data['end_time'] = !empty($_data['end_time']) ? strtotime($_data['end_time']) : '';
if ($_data['start_time'] > $_data['end_time']) {
return send_http_status(51000);
}
$_data['create_time'] = $_data['update_time'] = time();
$_data['user_id'] = USER_ID;
$_data = array_filter($_data);
$refected = Db::name($this->table_tenant)->strict(false)->insert($_data);
if ($refected && $_data['start_time'] && $_data['end_time']) {
//更新房间开始时间及结束时间
$where['id'] = $_data['room_id'];
Db::name($this->table_room)->where($where)->strict(false)->update($house_data);
//根据用户指定收费方式 切割时间
$_data['id'] = $_data['room_id']; //添加成功后的房间id
$this->crontab_room($_data, $_data['rent_type']);
}
return send_http_status(200);
}
/**
* 添加租户
*/
public function editTenant()
{
$_data = $this->request->post();
$_data['update_time'] = time();
$_data['user_id'] = USER_ID;
$_data = array_filter($_data);
$refected = Db::name($this->table_tenant)->strict(false)->update($_data);
if ($refected) {
return send_http_status(200);
}
return send_http_status(413);
}
/**
* 删除房源
* @param string $id
*/
public function delHouse($id = '')
{
if (!$id || !is_numeric($id)) {
return send_http_status(51003);
}
$affected = Db::name($this->table)->where('id', $id)->where('user_id', USER_ID)->update(['is_del' => 1]);
if ($affected) {
//删除房间数据
$this->delRoom('', $id);
return send_http_status(200);
}
return send_http_status(413);
}
/**
* 删除房间
* @param string $id 房间id
* @param string $house_id 一手房源id
* @return \type
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function delRoom($id = '', $house_id = '')
{
if ((!$id || !is_numeric($id)) && !$house_id) {
return send_http_status(51003);
}
//如果一手房源id存在,删除所有属于一手房源的子房间
$_where = !empty($house_id) ? 'house_id=' . $house_id : 'id=' . $id;
//(如果存在house_id说明执行了删除一手房源,即room_id为多个,所以这里需要根据house_id查询所有room_id)
if ($house_id) {
$id = Db::name($this->table_room)->where('house_id', $house_id)->field('id')->select();
$id = !empty($id) ? implode(',', array_column($id, 'id')) : '';
}
$affected = Db::name($this->table_room)->where($_where)->where('user_id', USER_ID)->update(['is_del' => 1]);
if ($affected) {
//删除租客
$this->delTenant('', $id);
return send_http_status(200);
}
return send_http_status(413);
}
/**
* 删除租客信息
* @param string $id 租客id
* @param string $room_id 所属房间id
* @return \type
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function delTenant($id = '', $room_id = '')
{
if ((!$id || !is_numeric($id)) && !$room_id) {
return send_http_status(51003);
}
//如果存在房间id,删除所有属于房间的租房用户
if (!empty($room_id)) {
$_where[] = ['room_id', 'in', $room_id]; //tp5.1 需要这样写
} else {
$_where = 'id=' . $id;
}
$affected = Db::name($this->table_tenant)->where($_where)->where('user_id', USER_ID)->update(['is_del' => 1]);
if ($affected) {
//删除租客
Db::name($this->table_order_room)->where('tenant_id', $id)->update(['is_del' => 1]);
//租客交费记录删除(没有总数据统计,可不删除)
return send_http_status(200);
}
return send_http_status(413);
}
/**
* 房间数据格式化
* @param $data
*/
static private function formatRoomData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
$v['days'] = time_days($v['end_time']);
$v['expire_days'] = isset($v['expire_time']) ? time_days($v['expire_time']) : '';
!empty($v['expire_time']) ? $v['expire_time'] = date('Y-m-d', $v['expire_time']) : $v['expire_time'] = '';
!empty($v['order_time']) ? $v['order_time'] = date('Y-m-d', $v['order_time']) : $v['order_time'] = '';
//列表封面
if (isset($v['photo'])) {
$_arr = explode(',', $v['photo']);
$v['thumb'] = !empty($_arr[0]) ? $_arr[0] : config('default_list_thumb');
}
});
}
/**
* 添加定时任务时间节点(定时任务短信提醒房租到期数据更新)
* @param $_data 房源数据
* @param int $month 指定分割月数
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function crontab($_data, $month = 3)
{
$start_time = $_data['start_time'];
$end_time = $_data['end_time'];
//计算指定天数后的时间戳
$_arr = [];
while ($start_time < $end_time) {
$arr_temp['house_id'] = $_data['id'];
$arr_temp['user_id'] = USER_ID;
$arr_temp['house_name'] = $_data['name'];
$arr_temp['phone'] = MEMBER['phone'];
$arr_temp['rent'] = $_data['rent'];
$arr_temp['address'] = $_data['province'] . $_data['city'] . $_data['area'];
$arr_temp['door_number'] = $_data['door_number'];
$arr_temp['create_time'] = $start_time = strtotime('+' . $month . ' month', $start_time);
$_arr[] = $arr_temp;
}
//删除最后一个元素,置换为end_time(防止开始时间与结束时间不一致)
$last_arr = array_pop($_arr);
$last_arr['create_time'] = $end_time;
$_arr[] = $last_arr;
//新增前先清空
$house_crontab = Db::name($this->table_house_crontab);
$house_crontab->where('house_id', $_data['id'])->where('user_id', USER_ID)->delete();
$house_crontab->insertAll($_arr);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
!empty($v['update_time']) ? $v['update_time'] = date('Y-m-d', $v['update_time']) : $v['update_time'] = '';
!empty($v['end_time']) ? $v['end_time'] = date('Y-m-d', $v['end_time']) : $v['end_time'] = '';
!empty($v['start_time']) ? $v['start_time'] = date('Y-m-d', $v['start_time']) : $v['start_time'] = '';
isset($v['sex']) ? $v['sex'] = config('sex')[$v['sex']] : '';
//列表封面
if (isset($v['photo'])) {
$_arr = explode(',', $v['photo']);
$v['thumb'] = !empty($_arr[0]) ? $_arr[0] : config('default_list_thumb');
}
});
}
static private function formatViewData(&$data)
{
if (!empty($data['housing_allocation'])) {
//获取房间配置
$housingAllocation = config('housingAllocation');
$data['housing_allocation_str'] = '';
//转换房间配置信息
$allocation_arr = explode(',', $data['housing_allocation']);
foreach ($allocation_arr as $k => $v) {
$data['housing_allocation_str'] .= $housingAllocation[$k]['name'] . ',';
}
$data['housing_allocation_str'] = trim($data['housing_allocation_str'], ',');
$data['housing_allocation'] = explode(',', $data['housing_allocation']);
}
if (!empty($data['photo'])) {
$data['imgList'] = explode(',', $data['photo']);
} else {
$data['imgList'] = [];
}
!empty($data['create_time']) ? $data['create_time'] = date('Y-m-d', $data['create_time']) : $data['create_time'] = '';
!empty($data['update_time']) ? $data['update_time'] = date('Y-m-d', $data['update_time']) : $data['update_time'] = '';
!empty($data['end_time']) ? $data['end_time'] = date('Y-m-d', $data['end_time']) : $data['end_time'] = '';
!empty($data['start_time']) ? $data['start_time'] = date('Y-m-d', $data['start_time']) : $data['start_time'] = '';
}
}

193
application/index/controller/Index.php

@ -0,0 +1,193 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\Controller;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class Index extends Controller
{
public $table = 'CloudHouse';//房源表
public $table_room = 'CloudHouseRoom';//子房间表
/**
* 首页API
*/
public function index()
{
// $_collection = new Collection();
// $_data['collection'] = $_collection->index();
$_data['room'] = $this->roomShare();
$user_id = $_SERVER['HTTP_USERID'];
if (empty($user_id)) {
$_data['expire_num'] = 0;
} else {
//房源类
$_house = new House();
//子房间到期数量
$_data['expire_num'] = $_house->expire_room(3, false);
//子房间到期数量
$_data['house_expire_num'] = $_house->expire(3, false);
}
return send_http_status(200, $_data);
}
/**
* 获取未出租共享房源
* @param int $num 公里数 默认为2
* @param int $latitude 纬度
* @param int $longitude 经度
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function roomShare()
{
$_search = $this->request->param('', '', 'filter_danger_str');
//判断是否含有 附近几公里的搜索条件
$num = $this->request->param('num', '', 'filter_danger_str');
$latitude = $this->request->param('latitude', '', 'filter_danger_str');
$longitude = $this->request->param('longitude', '', 'filter_danger_str');
$_db = Db::name($this->table_room);
if (!empty($num) && !empty($latitude) && !empty($longitude)) {
$distance = 1;
//查询附近几公里的一手房源数据
$sql = 'SELECT id,(
6371 * acos (
cos ( radians(' . $latitude . ') )
* cos( radians( latitude ) )
* cos( radians( longitude ) - radians(' . $longitude . ') )
+ sin ( radians(' . $latitude . ') )
* sin( radians( latitude ) )
)
) AS distance
FROM cloud_house
HAVING distance < ' . $num . '
ORDER BY distance
LIMIT 0 , 500';
$_house = Db::query($sql);
if (!empty($_house)) {
$house_ids = implode(array_column($_house, 'id'), ',');
}
//判断几公里搜索条件是否成立即 house_ids是否有值
$house_ids = !empty($house_ids) ? $house_ids : 0;
$_db->where('h.id', 'in', $house_ids);
}
//判断是否为会员
$user_id = $_SERVER['HTTP_USERID'];
// $vip_level = Db::name('cloud_member')->field('vip_level')->find($user_id);
// if (empty($vip_level) || $vip_level['vip_level'] < 1) {
// $_db->where('h.user_id', $user_id);
// }
//城市条件搜索
if (!empty($_search['province']) && empty($distance)) {
$_db->where('h.province', $_search['province']);
$_db->where('h.city', $_search['city']);
$_db->where('h.area', $_search['area']);
}
if (!empty($_search['search']) && empty($distance)) {
$_db->where('h.name', 'like', '%' . $_search['search'] . '%');
}
$_db->alias('r')->leftjoin(['cloud_house' => 'h'], 'r.house_id = h.id')->leftjoin('cloud_member m', 'r.user_id = m.id');
$_db->where('r.is_del', 0);
$_db->where('h.is_del', 0);
$_db->where(function ($query) {
$query->where('r.end_time', '=', 0);
$query->whereOr('r.end_time', '<', time());
});
$count = $_db->count();
$page = $this->request->param('page', 1, 'filter_danger_str');
$pagesize = $this->request->param('pagesize', 10, 'filter_danger_str');
$pages = ceil($count / $pagesize); //总页数
$_db->page($page, $pagesize)->order('r.id', "DESC");
$field = 'r.*,h.apartment,h.id AS house_id,h.name,h.name,h.photo,h.province,h.city,h.area,h.door_number,h.floor_num,m.phone';
$_result = $_db->field($field)->select();
self::formatRoomData($_result);
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return $_data;
}
/**
* 获取未出租共享房源 根据公里数
* @param int $num 公里数 默认为2
* @param int $latitude 纬度
* @param int $longitude 经度
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function roomShareLocation($num = 2, $latitude = '', $longitude = '')
{
}
/**
* 房间数据格式化
* @param $data
*/
static private function formatRoomData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
$v['days'] = time_days($v['end_time']);
//列表封面
if (isset($v['photo'])) {
$_arr = explode(',', $v['photo']);
$v['thumb'] = !empty($_arr[0]) ? $_arr[0] : config('default_list_thumb');
}
});
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
!empty($v['update_time']) ? $v['update_time'] = date('Y-m-d', $v['update_time']) : $v['update_time'] = '';
!empty($v['end_time']) ? $v['end_time'] = date('Y-m-d', $v['end_time']) : $v['end_time'] = '';
!empty($v['start_time']) ? $v['start_time'] = date('Y-m-d', $v['start_time']) : $v['start_time'] = '';
isset($v['sex']) ? $v['sex'] = config('sex')[$v['sex']] : '';
//列表封面
if (isset($v['photo'])) {
$_arr = explode(',', $v['photo']);
$v['thumb'] = !empty($_arr[0]) ? $_arr[0] : config('default_list_thumb');
}
});
}
}

106
application/index/controller/Login.php

@ -0,0 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use library\Controller;
use think\Db;
/**
* 用户登录
* Class Plugs
* @package app\admin\controller\api
*/
class Login extends Controller
{
private $table_member = 'CloudMember';
private $table_subaccount = 'CloudSubaccount';
/**
* 用户登录,先获取用户信息,再入库操作
* @return \type
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index()
{
$iv = $this->request->param('iv');
$encryptedData = $this->request->param('encryptedData');
$code = $this->request->param('code');
$config = config('appid');
//实例化类解密类
$crypt = \We::WeMiniCrypt($config);
$_data = $crypt->userInfo($code, $iv, $encryptedData);
if (isset($_data['openid'])) {
//先查询openid是否存在
$_result = Db::name($this->table_member)->where('openid', $_data['openid'])->find();
if ($_result) {
$_result['imgList'] = !empty($_result['qrcode']) ? explode(',', $_result['qrcode']) : '';
self::formatMemberData($_result);
return send_http_status(200, $_result);
}
$_data['headimg'] = $_data['avatarUrl'];
$_data['sex'] = $_data['gender'];
$_data['nickname'] = $_data['nickName'];
$_data['create_time'] = $_data['update_time'] = time();
if ($insert_id = Db::name($this->table_member)->strict(false)->insertGetId($_data)) {
$_data['id'] = $insert_id;
$_data['subaccount_id'] = 0;
return send_http_status(200, $_data);
}
return send_http_status(51006);
}
}
/**
* 子账号登录
*/
public function subaccount()
{
$_data = $this->request->post();
//比对账号密码
$_user = Db::name($this->table_subaccount)->where('username', $_data['username'])->where('status', 1)->find();
if (!$_user) {
return send_http_status(51012);
}
if ($_user['password'] != sha1($_data['password'])) {
return send_http_status(51012);
}
$_member = Db::name($this->table_member)->find($_user['user_id']);
if (!$_member) {
return send_http_status(415);
}
$_member['subaccount_id'] = $_user['id']; //赋值子账号id
self::formatMemberData($_member);
return send_http_status(200, $_member);
}
static private function formatMemberData(&$data)
{
if (!$data) {
return;
}
!empty($data['create_time']) ? $data['create_time'] = date('Y-m-d', $data['create_time']) : $data['create_time'] = '';
!empty($data['update_time']) ? $data['update_time'] = date('Y-m-d', $data['update_time']) : $data['update_time'] = '';
!empty($data['vip_time']) ? $data['vip_time'] = date('Y-m-d', $data['vip_time']) : $data['vip_time'] = '';
!empty($data['vip_endtime']) ? $data['vip_endtime'] = date('Y-m-d', $data['vip_endtime']) : $data['vip_endtime'] = '';
}
}

238
application/index/controller/Member.php

@ -0,0 +1,238 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class Member extends Base
{
private $table = 'CloudMember';
private $table_house = 'CloudHouse';
private $table_room = 'CloudHouseRoom';
public function __construct(App $app = null)
{
parent::__construct($app);
parent::auth();
}
/**
* 设置保洁
*/
public function setClean(){
$param = $this->request->param();
Db::name($this->table)->update(['id'=>$param['id'],'is_clean'=>$param['is_clean']]);
}
/**
* 获取管理用户列表
*/
public function index()
{
//判断当前用户是否为管理员
if (!MEMBER['is_manager']) {
return send_http_status(414);
}
$_where = 'status =1';
$count = Db::name($this->table)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 绑定用户手机号
*/
public function bindPhone()
{
$iv = $this->request->param('iv');
$encryptedData = $this->request->param('encryptedData');
$code = $this->request->param('code');
//获取小程序appid配置
$config = config('appid');
$crypt = \We::WeMiniCrypt($config);
//通过code获取 opendi及session_key
$_session = $crypt->session($code);
if (is_array($_session)) {
//解密用户数据
$_data = $crypt->decode($iv, $_session['session_key'], $encryptedData);
if (isset($_data['phoneNumber']) && !empty($_data['phoneNumber'])) {
//通过openid修改用户手机号
$affected = Db::name($this->table)->where('openid', $_session['openid'])->update(['phone' => $_data['phoneNumber']]);
if ($affected > -1) {
return send_http_status(200);
}
}
}
return send_http_status(51007);
}
/**
* 用户资料修改
*/
public function modify()
{
$_data = $this->request->post();
//添加房源数据
$_data = array_filter($_data);
$safe_data['pay_info'] = !empty($_data['pay_info']) ? $_data['pay_info'] : '';
$safe_data['phone'] = $_data['phone'];
$safe_data['qrcode'] = $_data['qrcode'];
$safe_data['truename'] = $_data['truename'];
$safe_data['card_number'] = $_data['card_number'];
$safe_data['update_time'] = time();
$safe_data['id'] = USER_ID;
$affected = Db::name($this->table)->strict(false)->update($safe_data);
if ($affected) {
$_member = Db::name($this->table)->find(USER_ID);
if (!empty($_member['qrcode'])) {
$_member['imgList'] = explode(',', $_member['qrcode']);
}
return send_http_status(200, $_member);
}
return send_http_status(413);
}
/**
* 会员详情
* @param string $id 会员id
* @return \type|void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data['member'] = Db::name($this->table)->find($id);
if ($_data['member']) {
//查询所有房源数据
$_data['house_count'] = Db::name($this->table_house)->where('is_del', 0)->where('user_id', $_data['member']['id'])->count();
$_data['room_count'] = Db::name($this->table_room)->where('is_del', 0)->where('user_id', $_data['member']['id'])->count();
$_data['vip_level'] = config('vip_level');
}
self::formatViewData($_data['member']);
return send_http_status(200, $_data);
}
/**
* 获取用户信息
* @param string $id
* @return \type
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getInfo($id = '')
{
//先查询openid是否存在
$_result = Db::name($this->table)->where('id', $id)->find();
if ($_result) {
$_result['imgList'] = !empty($_result['qrcode']) ? explode(',', $_result['qrcode']) : '';
self::formatViewData($_result);
return send_http_status(200, $_result);
}
}
/**
* 修改会员等级
* @param string $user_id 被修改的用户id
* @param int $level 修改等级
* @return \type
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function level($user_id = '', $level = 0)
{
if (!$user_id || !is_numeric($user_id) || !in_array($level, [0, 1, 2, 3])) {
return send_http_status(51005);
}
//判断当前用户是否为管理员
if (!MEMBER['is_manager']) {
return send_http_status(414);
}
$affected = Db::name($this->table)->where('id', $user_id)->update(['vip_level' => $level, 'vip_time' => time()]);
return send_http_status(200);
}
/**
* 修改会员状态
* @param string $user_id 被修改的用户id
* @return \type
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function del($id = '')
{
if (!$id || !is_numeric($id)) {
return send_http_status(51003);
}
//判断当前用户是否为管理员
if (!MEMBER['is_manager']) {
return send_http_status(414);
}
$affected = Db::name($this->table)->where('id', $id)->update(['status' => 0]);
return send_http_status(200);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
$vip_level = config('vip_level');
array_walk($data, function (&$v, &$k) use ($vip_level) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
!empty($v['update_time']) ? $v['update_time'] = date('Y-m-d', $v['update_time']) : $v['update_time'] = '';
!empty($v['vip_time']) ? $v['vip_time'] = date('Y-m-d', $v['vip_time']) : $v['vip_time'] = '';
isset($v['sex']) ? $v['sex'] = config('sex')[$v['sex']] : '';
//列表封面
if (isset($v['vip_level'])) {
$v['vip_level_color'] = $vip_level[$v['vip_level']]['color'];
$v['vip_level'] = $vip_level[$v['vip_level']]['name'];
}
});
}
static private function formatViewData(&$data)
{
!empty($data['create_time']) ? $data['create_time'] = date('Y-m-d', $data['create_time']) : $data['create_time'] = '';
!empty($data['update_time']) ? $data['update_time'] = date('Y-m-d', $data['update_time']) : $data['update_time'] = '';
!empty($data['vip_time']) ? $data['vip_time'] = date('Y-m-d', $data['vip_time']) : $data['vip_time'] = '';
!empty($data['vip_endtime']) ? $data['vip_endtime'] = date('Y-m-d', $data['vip_endtime']) : $data['vip_endtime'] = '';
$data['vip_level_str'] = config('vip_level')[$data['vip_level']]['name'];
$data['vip_level_color'] = config('vip_level')[$data['vip_level']]['color'];
}
}

67
application/index/controller/Notify.php

@ -0,0 +1,67 @@
<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
class Notify extends Controller{
public function clean(){
$wechat = new \WeChat\Pay(config('wechat.miniapp'));
// 4. 获取通知参数
$data = $wechat->getNotify();
//file_put_contents('./wechat_pay.log', var_export($data,true),FILE_APPEND);
if ($data['return_code'] === 'SUCCESS' && $data['result_code'] === 'SUCCESS') {
// @todo 去更新下原订单的支付状态
$order_no = $data['out_trade_no'];
$update = [
'order_no'=>$order_no,
'pay_money'=>$data['total_fee'] / 100,
'pay_time'=>time(),
'transaction_no'=>$data['transaction_id'],
'state'=> 1,
];
try {
$res = Db::name('CloudCleanOrder')->where('order_no',$order_no)->update($update);
if ($res){
$this->selectClean($order_no, $data['openid']);
// 返回接收成功的回复
ob_clean();
echo $wechat->getNotifySuccessReply();
}
}catch (\Throwable $e){
file_put_contents('./wechat_pay.log', $e->getMessage(),FILE_APPEND);
}
}
}
/**
* 分配保洁
*/
public function selectClean($order_no = 0,$openid = 0){
$sql = Db::name('CloudCleanOrder')
->alias('o')
->where('m.openid',Db::raw('o.service_openid'))
->where('complete','<',Db::raw('second'))
->field('count(*)')
->buildSql();
$clean = Db::name('CloudMember')
->alias('m')
->field($sql.' as counts,m.id, m.openid, m.nickname')
->where('is_clean',1)
->where('m.openid','<>',$openid)
->order('counts','asc')
->order('id','asc')
->select();
if (!$clean) {
file_put_contents('./wechat_pay.log', "\nnot find cleaner\n",FILE_APPEND);
return false;
}
$first = current($clean);
Db::name('CloudCleanOrder')->where('order_no',$order_no)->update(['service_openid'=>$first['openid']]);
//dump($res);
}
}

233
application/index/controller/Order.php

@ -0,0 +1,233 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 订单管理
* Class Index
* @package app\index\controller
*/
class Order extends Base
{
private $table = 'CloudOrder';
private $table_tenant_order = 'CloudOrderRoom';
private $table_room = 'CloudHouseRoom';
private $table_member = 'CloudMember';
public function __construct(App $app = null)
{
parent::__construct($app);
parent::auth();
}
/**
* 获取订单列表
*/
public function index()
{
//判断当前用户是否为管理员
if (!MEMBER['is_manager']) {
$_where = 'user_id = ' . USER_ID;
} else {
$_where = '';
}
$count = Db::name($this->table)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 统计房源所有收入或者该房间收入
* @param string $room_id 指定房间id 不指定默认所有房
* @param string $id 指定房源id
* @return float
*/
public function orderAmount($room_id = '', $house_id = '')
{
$_where['user_id'] = USER_ID;
$_where['status'] = 1;
if ($room_id) {
$_where['room_id'] = $room_id;
}
$_db = Db::name($this->table_tenant_order)->where($_where);
if ($house_id) {
//查询此房源下面的子房间数据
$id_arr = Db::name($this->table_room)->where('house_id', $house_id)->column('id');
if (empty($id_arr)) {
return 0;
}
$_db->where('room_id', 'in', implode(',', $id_arr));
}
$count = $_db->sum('price');
return $count;
}
/**
* 获取租户订单
*/
public function tenant()
{
$_where['user_id'] = USER_ID;
$phone = $this->request->param('phone', '');
$room_id = $this->request->param('room_id', '');
if ($phone) {
$_where['phone'] = $phone;
}
if ($room_id) {
$_where['room_id'] = $room_id;
}
$_where['is_del'] = 0;
$count = Db::name($this->table_tenant_order)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table_tenant_order)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 新增vip开通订单
*/
public function add()
{
$_data = $this->request->post();
$config = config('vip_level');
//添加房源数据
$_data = array_filter($_data);
$_data['status'] = 0;
$_data['price'] = !empty($_data['vip_level']) ? $config[$_data['vip_level']]['price'] : '0';
$_data['create_time'] = $_data['update_time'] = time();
$_data['user_id'] = USER_ID;
$affected = Db::name($this->table)->strict(false)->insert($_data);
if ($affected) {
return send_http_status(200);
}
return send_http_status(51008);
}
/**
* 修改订单状态
*/
public function edit()
{
//判断当前用户是否为管理员
if (!MEMBER['is_manager']) {
return send_http_status(414);
}
$_data = $this->request->post();
if (!isset($_data['id']) || !is_numeric($_data['id'])) {
return send_http_status(51005);
}
$_data = array_filter($_data);
$_data['update_time'] = time();
$affected = Db::name($this->table)->strict(false)->update($_data);
if ($affected) {
//如果订单修改成功,且为审核通过 执行会员状态更新
if ($_data['status'] == 1) {
//查询当前订单等级
$_order = Db::name($this->table)->where('id', $_data['id'])->find();
$_member['vip_time'] = $_member['update_time'] = time();
$_member['vip_endtime'] = strtotime('+1 year');
$_member['vip_level'] = $_order['vip_level'];
$_member['id'] = $_order['user_id'];
Db::name($this->table_member)->strict(false)->update($_member);
}
return send_http_status(200);
}
return send_http_status(51009);
}
/**
* 修改租户订单状态
*/
public function tenantEdit()
{
$_data = $this->request->post();
if (!isset($_data['id']) || !is_numeric($_data['id'])) {
return send_http_status(51005);
}
$_data = array_filter($_data);
$_data['update_time'] = time();
$affected = Db::name($this->table_tenant_order)->strict(false)->update($_data);
if ($affected) {
//如果订单修改成功,且为审核通过 执行当前房自动续费
if ($_data['status'] == 1) {
//查询订单中增加的确认日期
$_order = Db::name($this->table_tenant_order)->where('status', 1)->field('room_id,rent_type')->find($_data['id']);
if (empty($_order)) {
return send_http_status(51013);
}
//先查询此房的开始及结束日期
$_room = Db::name($this->table_room)->where('is_del', 0)->find($_order['room_id']);
if (!$_room) {
return send_http_status(51015);
}
$month = $_order['rent_type']; //增加的月数
//判断原房间 结束日期是否为空或者是否已过期
// $second = $_room['end_time'] + ($month * 30 * 24 * 60 * 60); //把月时间换成秒单位 并添加到现有有时间戳
$second = $_room['end_time'];
$now_month = strtotime('+' . $month . ' month'); //以当前时间往后累计指定的$month
$end_time = empty($_room['end_time']) || $_room['end_time'] < time() ? $now_month : $second;
//增加此房间的到期日期
$start_end_time = [
'id' => $_order['room_id'],
'start_time' => time(),
'end_time' => $end_time,
];
// if (!Db::name($this->table_room)->update($start_end_time)) {
// return send_http_status(51014);
// }
//修改定时任务提醒
// $this->crontab_room($start_end_time, $month);
}
return send_http_status(200);
}
return send_http_status(51009);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
$vip_level = config('vip_level');
$pay_type = config('pay_type');
array_walk($data, function (&$v, &$k) use ($vip_level, $pay_type) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
!empty($v['update_time']) ? $v['update_time'] = date('Y-m-d', $v['update_time']) : $v['update_time'] = '';
!empty($v['start_time']) ? $v['start_time'] = date('Y-m-d', $v['start_time']) : $v['start_time'] = '';
!empty($v['end_time']) ? $v['end_time'] = date('Y-m-d', $v['end_time']) : $v['end_time'] = '';
//支付方式
if (isset($v['price'])) {
$v['pay_type'] = $pay_type[$v['pay_type']]['name'];
}
});
}
}

187
application/index/controller/Pay.php

@ -0,0 +1,187 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2018/11/15 9:47
* +----------------------------------------------------------------------
* Des: 短信插件
+----------------------------------------------------------------------*/
namespace app\index\controller;
use think\Controller;
use think\Db;
class Pay extends Controller
{
/**
* 房源表
* @var string
*/
private $table_house = 'CloudHouse';
/**
* 房间表
* @var string
*/
private $table_room = 'CloudHouseRoom';
/**
* 合同表
* @var string
*/
private $table_contract = 'CloudHouseContract';
/**
* 租户表
* @var string
*/
private $table_tenant = 'CloudHouseTenant';
/**
* 租户表
* @var string
*/
private $table_member = 'CloudMember';
/**
* 租户表
* @var string
*/
private $table_order = 'CloudOrderRoom';
/**
* 支付页面
* @param int $roomid 房间id
*/
public function index()
{
$roomid = $this->request->param('roomid', 0);
$phone = $this->request->param('phone', 0);
if (!$roomid || !is_numeric($roomid)) {
return '房间信息不存在';
}
if (!$phone || !is_numeric($phone)) {
return '手机号不正确';
}
//查找房间及房源数据
$_data = Db::name($this->table_room)->alias('r')->join('cloud_house h', 'r.house_id = h.id')->where('r.is_del', 0)->field('r.*,h.name AS house_name,h.door_number,h.water_money,h.gas_money')->find($roomid);
if (empty($_data)) {
return '房间信息不存在';
}
$_data['rent_type_name'] = config('rent_type')[$_data['rent_type']];
//查找当前房间有多少人
$tenant_num = Db::name($this->table_tenant)->where('room_id', $roomid)->where('is_del', 0)->count();
//查找当前租户信息
$_tenant = Db::name($this->table_tenant)->where('phone', $phone)->where('is_del', 0)->find();
if (empty($_tenant)) {
return '租户信息不存在';
}
//查找当前二房东收款账号
$_holder = Db::name($this->table_member)->where('id', $_data['user_id'])->find();
if (empty($_holder)) {
return '二房东信息不存在';
}
if (empty($_holder['qrcode'])) {
//return '收款信息不存在!!!';
}
$qrcode = explode(',', $_holder['qrcode']);
$_holder['pay1'] = !empty($qrcode[0]) ? $qrcode[0] : '';
$_holder['pay2'] = !empty($qrcode[1]) ? $qrcode[1] : '';
//查询支付记录表,计算当前押一付三 ,如果第一次支付 需要x4 如果是续租需要x3
$order_num = Db::name($this->table_order)->where('room_id', $_data['id'])->where('is_del', 0)->where('status', 1)->count();
$rent_type = $_data['rent_type'];
$_data['broadband_fee'] = empty($_data['broadband_fee']) ? 0 : $_data['broadband_fee'];
$_data['property_fee'] = empty($_data['property_fee']) ? 0 : $_data['property_fee'];
$_data['key_deposit'] = empty($_data['key_deposit']) ? 0 : $_data['key_deposit'];
$_data['total_rent'] = ($_data['rent'] + $_data['broadband_fee'] + $_data['property_fee'] + ($_data['water_money'] + $_data['gas_money']) * $tenant_num) * $rent_type;
//计算公式: (月租+物业费+宽带费+(水费+燃气费)x户数)x月数 + 钥匙押金x户数
//计算公式[改版本]: (月租+物业费+宽带费+(水费+燃气费)x户数)x月数 + 钥匙押金x户数 $_data['key_deposit'] * $tenant_num
if (empty($order_num)) {
//$_data['total_rent'] += $_data['rent']; //如果之前没有订单加一个月的租金
}
//合同开始时间
$_data['contract_starttime_str'] = date('Y年m月d日');
$_data['contract_endtime_str'] = date('Y年m月d日', strtotime('+ ' . $_data['rent_type'] . ' month'));
$_data['contract_starttime'] = time();
$_data['contract_endtime'] = strtotime('+ ' . $_data['rent_type'] . ' month');
//合同编号
$_data['contract_number'] = 'YYT-' . date('YmdHis');
$this->assign('data', $_data);
$this->assign('holder', $_holder);
$this->assign('tenant_num', $tenant_num);
$this->assign('deposit', $order_num > 0 ? 0 : 1); //押金
$this->assign('tenant', $_tenant);
$this->assign('rent_type', $rent_type);
return $this->fetch();
}
/**
* 订单提交
*/
public function add()
{
$_data = $this->request->post();
//通过房间查找用户user_id,确认是否存在
$_room = Db::name($this->table_room)->where('id', $_data['room_id'])->where('is_del', 0)->find();
if (empty($_room)) {
return $this->error('房间号不存在');
}
unset($_data['status']);
//先清空原有订单数据
$room_order_db = Db::name($this->table_order);
$room_order_db->where('room_id', $_room['id']);
$room_order_db->where('name', $_data['name']);
$room_order_db->update(['is_del' => 1]);
$_data['create_time'] = $_data['update_time'] = time();
$_data['user_id'] = $_room['user_id'];
$start_time = $_room['start_time'];
$end_time = $_room['end_time'];
//计算指定天数后的时间戳
if ($start_time >= $end_time) {
return $this->error('房间开始时间必需小于结束时间');
}
$_arr = [];
while ($start_time < $end_time) {
$_data['room_id'] = $_room['id'];
$_data['start_time'] = $start_time;
$_data['end_time'] = $start_time = strtotime('+' . $_room['rent_type'] . ' month', $start_time);
$_arr[] = $_data;
}
if (empty($_arr)) {
return $this->error('未知错误!!!');
}
//判断是否存在订单,如果存在代表包含押一的金额,否则不包含
$order_num = Db::name($this->table_order)->where('room_id', $_room['id'])->where('is_del', 0)->where('status', 1)->count();
if (empty($order_num)) {
(int)$_arr[0]['price'] += (int)$_data['rent_price']; //加上一个月租金 即押一
(int)$_arr[0]['price'] += (int)$_data['key_deposit'] * (int)$_data['tenant_num']; //加上一个月钥匙押金 即押一
$_arr[0]['detail'] .= '<br /> 房租押金:' . $_data['rent_price'] . '元'; //加上押金、钥匙押金
$_arr[0]['detail'] .= '<br /> 钥匙押金:' . (int)$_data['key_deposit'] * (int)$_data['tenant_num'] . '元'; //加上押金、钥匙押金
}
//删除最后一个元素,置换为end_time(防止开始时间与结束时间不一致)
$last_arr = array_pop($_arr);
$last_arr['end_time'] = $end_time;
$_arr[] = $last_arr;
//插入新订单数据
$affected = Db::name($this->table_order)->strict(false)->insertAll($_arr);
if ($affected) {
//在线合同
//Db::name($this->table_contract)->strict(false)->insert($_data);
return $this->success('订单提交成功');
}
return $this->error('订单提交失败');
}
}

73
application/index/controller/Question.php

@ -0,0 +1,73 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 问题管理
* Class Index
* @package app\index\controller
*/
class Question extends Base
{
private $table = 'CloudQuestion';
/**
* 获取问题列表
*/
public function index()
{
$count = Db::name($this->table)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->page($page, $pagesize)->order('id', "DESC")->where('status',1)->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 合同详情
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data = Db::name($this->table)->find($id);
return send_http_status(200, $_data);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
});
}
}

42
application/index/controller/Single.php

@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 应用入口
* Class Index
* @package app\index\controller
*/
class Single extends Base
{
protected $table = 'CloudSingle';
/**
* 获取单页面数据
* @param string $ident 单页面唯一标签
*/
public function index($ident = '')
{
$_data = Db::name($this->table)->where('ident', $ident)->find();
return send_http_status(200, $_data);
}
}

34
application/index/controller/Sms.php

@ -0,0 +1,34 @@
<?php
/*----------------------------------------------------------------------
* 项目名称: CloudAdmin
* +----------------------------------------------------------------------
* 版权所有: 2014~2020 安徽云掌开发团队
* +----------------------------------------------------------------------
* 官方网站: [ http://www.yaoyz.com、http://www.ahyunzhang.com ]
* +----------------------------------------------------------------------
* Date: 2018/11/15 9:47
* +----------------------------------------------------------------------
* Des: 短信插件
+----------------------------------------------------------------------*/
namespace app\index\controller;
use think\Controller;
class Sms extends Controller
{
/**
* 默认操作数据表
* @var string
*/
public $table = 'sms';
public function index()
{
$_result = \app\api\controller\Sms::sendNotify('13965108697', ['{url}' => 'http://www.baidu.com'], 23);
dump($_result);
}
}

127
application/index/controller/Subaccount.php

@ -0,0 +1,127 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use think\App;
use think\Db;
/**
* 子账号管理
* Class Index
* @package app\index\controller
*/
class Subaccount extends Base
{
private $table = 'CloudSubaccount';
public function __construct(App $app = null)
{
parent::__construct($app);
parent::auth();
}
/**
* 获取子账号列表
*/
public function index()
{
$_where = 'user_id = ' . USER_ID;
$count = Db::name($this->table)->where($_where)->count();
$page = $this->request->param('page', 1);
$pagesize = $this->request->param('pagesize', 10);
$pages = ceil($count / $pagesize); //总页数
$_result = Db::name($this->table)->where($_where)->page($page, $pagesize)->order('id', "DESC")->select();
$_data['list'] = $_result;
$_data['pages'] = $pages;
self::formatData($_data['list']);
return send_http_status(200, $_data);
}
/**
* 子账号详情
*/
public function view($id = '')
{
if (!$id) {
return;
}
//获取房源详情
$_data = Db::name($this->table)->where('user_id', USER_ID)->find($id);
return send_http_status(200, $_data);
}
/**
* 添加子账号
*/
public function add()
{
$_data = $this->request->post();
$_data['create_time'] = $_data['update_time'] = time();
$_data['password'] = sha1($_data['password']);
$_data['user_id'] = USER_ID;
$_data = array_filter($_data);
//先查询账号是否存在
$_user = Db::name($this->table)->where('username', $_data['username'])->find();
if ($_user) {
return send_http_status(51010);
}
//查询已有账号的数量
$count = Db::name($this->table)->where('user_id', USER_ID)->where('status', 1)->count();
$_config = config('vip_level');
if ($count > $_config[MEMBER['vip_level']]['subaccount_count']) {
return send_http_status(51011);
}
$affected = Db::name($this->table)->strict(false)->insert($_data);
if (!$affected) {
return send_http_status(51002);
}
return send_http_status(200);
}
/**
* 修改子账号
*/
public function edit()
{
$_data = $this->request->post();
$_data['update_time'] = time();
$_data['user_id'] = USER_ID;
if ($_data['password'] == '***123***') {
unset($_data['password']);
}else{
$_data['password'] = sha1($_data['password']);
}
$affected = Db::name($this->table)->strict(false)->update($_data);
if (!$affected) {
return send_http_status(51002);
}
return send_http_status(200);
}
static private function formatData(&$data)
{
if (!$data) {
return;
}
array_walk($data, function (&$v, &$k) {
!empty($v['create_time']) ? $v['create_time'] = date('Y-m-d', $v['create_time']) : $v['create_time'] = '';
});
}
}

104
application/index/controller/Upload.php

@ -0,0 +1,104 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\index\controller;
use library\Controller;
use library\File;
/**
* 后台插件管理
* Class Plugs
* @package app\admin\controller\api
*/
class Upload extends Controller
{
public function index()
{
return $this->fetch();
}
/**
* 系统选择器图标
*/
public function icon()
{
$this->title = '图标选择器';
$this->field = input('field', 'icon');
$this->fetch();
}
/**
* Plupload 插件上传文件
* @return \think\response\Json
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function plupload()
{
if (!($file = $this->getUploadFile()) || empty($file)) {
return json(['uploaded' => false, 'error' => ['message' => '文件上传异常,文件可能过大或未上传']]);
}
if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
return json(['uploaded' => false, 'error' => ['message' => '文件上传类型受限,请在后台配置']]);
}
if ($file->checkExt('php,sh')) {
return json(['uploaded' => false, 'error' => ['message' => '可执行文件禁止上传到本地服务器']]);
}
$this->safe = boolval(input('safe'));
$this->uptype = 'local';
$this->extend = pathinfo($file->getInfo('name'), PATHINFO_EXTENSION);
$pre = date('Y-m') . '/' . date('d');
$name = File::name($file->getPathname(), $this->extend, $pre, 'md5_file');
$info = File::instance($this->uptype)->save($name, file_get_contents($file->getRealPath()), $this->safe);
if (is_array($info) && isset($info['url'])) {
return json(['uploaded' => true, 'filename' => $name, 'url' => $this->safe ? $name : $info['url']]);
} else {
return json(['uploaded' => false, 'error' => ['message' => '文件处理失败,请稍候再试!']]);
}
}
/**
* 获取文件上传方式
* @return string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function getUploadType()
{
$this->uptype = input('uptype');
if (!in_array($this->uptype, ['local', 'oss', 'qiniu'])) {
$this->uptype = sysconf('storage_type');
}
return $this->uptype;
}
/**
* 获取本地文件对象
* @return \think\File
*/
private function getUploadFile()
{
try {
return $this->request->file('file');
} catch (\Exception $e) {
$this->error(lang($e->getMessage()));
}
}
}

212
application/index/view/pay/index.html

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>房租收费系统</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="/static/plugs/layui/css/layui.css" media="all">
<link rel="stylesheet" type="text/css" href="/static/plugs/wangedit/css/wangEditor-mobile.css">
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
.saveimg {
text-align: center;
}
.saveimgs span {
display: inline-block;
margin-top: 5px;
}
.det-nr {
line-height: 250%;
padding: 20px 30px 20px 20px;
}
.underline {
text-decoration: underline;
}
</style>
</head>
<body>
<div style="padding:20px;">
<fieldset class="layui-elem-field layui-field-title">
<legend>房租费用明细</legend>
</fieldset>
<form class="layui-form layui-form-pane" method="post" action="{:url('index/pay/add')}">
<div class="layui-form-item">
<label class="layui-form-label">小区门牌号</label>
<div class="layui-input-block">
<input type="text" name="door_number" readonly="readonly"
value="{$data.house_name}-{$data.door_number}"
autocomplete="off"
placeholder="请输入标题"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">房间号</label>
<div class="layui-input-block">
<input type="text" name="room_number" readonly="readonly" value="{$data.room_number}"
autocomplete="off"
placeholder="请输入房间号"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机号</label>
<div class="layui-input-block">
<input type="text" name="phone" lay-verify="required|phone" value="{$Think.get.phone|default=''}"
autocomplete="off"
placeholder="请输入手机号"
class="layui-input">
<input type="hidden" name="room_id" value="{$Think.get.roomid|default=''}"
class="layui-input">
<input type="hidden" name="name" value="{$tenant.name}"
class="layui-input">
<input type="hidden" name="tenant_id" value="{$tenant.id}"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">租金</label>
<div class="layui-input-block">
<input type="text" name="rent" readonly="readonly" value="{$data.rent}元"
autocomplete="off"
placeholder="请输入租金"
class="layui-input">
<input type="hidden" name="rent_price" value="{$data.rent}"
class="layui-input">
<input type="hidden" name="key_deposit" value="{$data.key_deposit}"
class="layui-input">
<input type="hidden" name="tenant_num" value="{$tenant_num}"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">钥匙押金:</label>
<div class="layui-input-block">
<input type="text" name="" readonly="readonly" value="{$data.key_deposit}元/人"
autocomplete="off"
placeholder="钥匙押金"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">燃气费</label>
<div class="layui-input-block">
<input type="text" name="gas_money" readonly="readonly"
value="{$data.gas_money}元/人 x {$tenant_num}人={$data.gas_money * $tenant_num}元"
autocomplete="off"
placeholder="请输入燃气费"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">水费</label>
<div class="layui-input-block">
<input type="text" name="water_money" readonly="readonly"
value="{$data.water_money}元/人 x {$tenant_num}人={$data.water_money * $tenant_num}元"
autocomplete="off"
placeholder="请输入水费"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">交租方式</label>
<div class="layui-input-block">
<input type="text" name="rent_type_name" readonly="readonly" value="{$data.rent_type_name}"
autocomplete="off"
class="layui-input">
<input type="hidden" name="rent_type" readonly="readonly" value="{$data.rent_type}"
autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" style="color: red;">房租合计:</label>
<div class="layui-input-block">
<textarea name="detail" rows="6" class="layui-textarea">(租金:{$data.rent}元 + 宽带费:{$data.broadband_fee}元 + 物业费:{$data.property_fee}元 + 燃气费:{$data.gas_money}元 x {$tenant_num}人 + 水费:{$data.water_money}元 x {$tenant_num}人) x {$rent_type}个月 = 合计:{$data.total_rent}元
</textarea>
<input type="hidden" name="price" readonly="readonly"
value="{$data.total_rent}"
autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
{if $Think.get.sms eq true}
<a href="sms://{$Think.get.phone|default=''}" id="sms-text" class="layui-btn layui-bg-orange">发送短信</a>
{else}
<button class="layui-btn layui-bg-blue" lay-submit="" lay-filter="demo1">确认生成订单</button>
{/if}
</div>
</div>
</form>
</div>
<script src="/static/plugs/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="/static/plugs/wangedit/js/lib/zepto.js"></script>
<script type="text/javascript" src="/static/plugs/wangedit/js/lib/zepto.touch.js"></script>
<script type="text/javascript">
$(function () {
// 浏览器的用户代理报头
let u = navigator.userAgent;
let smsurl = '';
// 短信内容需要转码
var smstextArea = encodeURIComponent("您的房租即将到期(租金:{$data.rent}元 + 燃气费:{$data.gas_money}元 x {$tenant_num}/人 + 水费:{$data.water_money}元 x {$tenant_num}/人) x {$rent_type}月({$data.rent_type_name}) = {$data.total_rent}元,请通过支付宝或者微信转账,有什么疑问可直接联系我!");
var smsphone = $('#sms-text').attr('href');
if (/(iPhone|iPad|iPod|iOS)/i.test(u)) {
$('#sms-text').attr('href', smsphone + '&body=' + smstextArea);
} else {
$('#sms-text').attr('href', smsphone + '?body=' + smstextArea);
}
// 自定义配置
editor.config.uploadImgUrl = '/upload';
// editor.config.menus = ['bold', 'quote', 'list','img'];
// 初始化
editor.init();
console.log(editor.$txt);
});
</script>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
<script>
layui.use(['form', 'layedit', 'laydate'], function () {
var form = layui.form
, layer = layui.layer;
//监听提交
form.on('submit(demo1)', function (data) {
});
});
</script>
</body>
</html>

439
application/index/view/pay/index合同版本.html

@ -0,0 +1,439 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>房租收费系统</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="/static/plugs/layui/css/layui.css" media="all">
<link rel="stylesheet" type="text/css" href="/static/plugs/wangedit/css/wangEditor-mobile.css">
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
.saveimg {
text-align: center;
}
.saveimgs span {
display: inline-block;
margin-top: 5px;
}
.det-nr {
line-height: 250%;
padding: 20px 30px 20px 20px;
}
.underline {
text-decoration: underline;
}
</style>
</head>
<body>
<div style="padding:20px;">
<fieldset class="layui-elem-field layui-field-title">
<legend>房租费用明细</legend>
</fieldset>
<form class="layui-form layui-form-pane" method="post" action="{:url('index/pay/add')}">
<div class="layui-form-item">
<label class="layui-form-label">小区门牌号</label>
<div class="layui-input-block">
<input type="text" name="door_number" readonly="readonly"
value="{$data.house_name}-{$data.door_number}"
autocomplete="off"
placeholder="请输入标题"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">房间号</label>
<div class="layui-input-block">
<input type="text" name="room_number" readonly="readonly" value="{$data.room_number}"
autocomplete="off"
placeholder="请输入房间号"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机号</label>
<div class="layui-input-block">
<input type="text" name="phone" lay-verify="required|phone" value="{$Think.get.phone|default=''}"
autocomplete="off"
placeholder="请输入手机号"
class="layui-input">
<input type="hidden" name="room_id" value="{$Think.get.roomid|default=''}"
class="layui-input">
<input type="hidden" name="name" value="{$tenant.name}"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">租金</label>
<div class="layui-input-block">
<input type="text" name="rent" readonly="readonly" value="{$data.rent}元"
autocomplete="off"
placeholder="请输入租金"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">燃气费</label>
<div class="layui-input-block">
<input type="text" name="gas_money" readonly="readonly"
value="{$data.gas_money}元/人 x {$tenant_num}人={$data.gas_money * $tenant_num}元"
autocomplete="off"
placeholder="请输入燃气费"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">水费</label>
<div class="layui-input-block">
<input type="text" name="water_money" readonly="readonly"
value="{$data.water_money}元/人 x {$tenant_num}人={$data.water_money * $tenant_num}元"
autocomplete="off"
placeholder="请输入水费"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">交租方式</label>
<div class="layui-input-block">
<input type="text" name="rent_type_name" readonly="readonly" value="{$data.rent_type_name}"
autocomplete="off"
placeholder="请输入交租方式"
class="layui-input">
<input type="hidden" name="rent_type" readonly="readonly" value="{$data.rent_type}"
autocomplete="off"
placeholder="请输入交租方式"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" style="color: red;">房租合计:</label>
<div class="layui-input-block">
<input type="text" name="detail" style="color: red;font-weight: bold;" readonly="readonly"
value="(租金{$data.rent} + 燃气费{$data.gas_money} x {$tenant_num} + 水费{$data.water_money} x {$tenant_num}) x {$rent_type}月({$data.rent_type_name}) = {$data.total_rent}元"
autocomplete="off"
placeholder="请输入标题"
class="layui-input">
<input type="hidden" name="price" readonly="readonly"
value="{$data.total_rent}"
autocomplete="off"
class="layui-input">
<p style="padding:10px 0;">
<img src="{$holder.pay1}" width="180" style="margin-right: 100px;"/>
<img src="{$holder.pay2}" width="180"/>
</p>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">支付方式</label>
<div class="layui-input-block">
<input type="radio" name="pay_type" value="1" title="微信">
<input type="radio" name="pay_type" value="2" title="支付宝">
</div>
</div>
<fieldset class="layui-elem-field layui-field-title" style="margin:30px 0;">
<legend>在线合同签约</legend>
</fieldset>
<div class="layui-form-item" pane>
<label class="layui-form-label">合同编号</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="number" value="{$data.contract_number}">
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">签约小区</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="house_name" value="{$data.house_name}">
</div>
</div>
<input type="hidden" name="contract_starttime" readonly="readonly"
value="{$data.contract_starttime|default=''}"
autocomplete="off"
class="layui-input">
<input type="hidden" name="contract_endtime" readonly="readonly"
value="{$data.contract_endtime|default=''}"
autocomplete="off"
class="layui-input">
<div class="layui-form-item" pane>
<div class="">
<textarea id="textarea1" name="content" style="width:100%;height:100%;">
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
.saveimg {
text-align: center;
}
.saveimgs span {
display: inline-block;
margin-top: 5px;
}
.det-nr {
line-height: 160%;
padding: 20px 30px 20px 20px;
}
.underline {
text-decoration: underline;
}
</style>
<div class="det-nr mt20">
<p style="text-indent:2em;">甲方姓名(出租方):
<span class="underline"><b>{$holder.truename}</b></span>
身份证号码:<span class="underline"><b>{$holder.card_number}</b>
</span>
</p>
<p style="text-indent:2em;">乙方姓名(承租方):
<span class="underline">{$tenant.name}</span> 身份证号码:
<span class="underline">{$tenant.card_id}</span>
</p>
<p style="text-indent:2em;">经双方协商甲方将位于 <span
class="underline"> {$data.contract_starttime_str|default=''}</span> 房屋出租给乙方居住使用。</p>
<p style="text-indent:2em;">一、租房从
<span class="underline"> {$data.contract_starttime_str|default=''}</span> 起至
<span class="underline"> {$data.contract_endtime_str|default=''}</span>止。</p>
<p style="text-indent:2em;">二、月租金为 <span class="underline">{$data.rent}</span> 元,缴租为 <span
class="underline">{$data.rent_type}</span> 个月支付一次,以后应提前 <span class="underline">15</span>
天支付。</p>
<p style="text-indent:2em;">三、约定事项</p>
<p style="text-indent:2em;">1、乙方入住时,应及时更换门锁若发生意外与甲方无关。因不慎或使用不当引起火灾、电、气灾害等非自然灾害所造成损失由乙方负责。</p>
<p style="text-indent:2em;">
2、乙方无权转租、转借、转卖该房屋,及屋内家具家电,不得擅自改动房屋结构,爱护屋内设施,如有人为原因造成破损丢失应维修完好,否则照价赔偿。并做好防火,防盗,防漏水,和阳台摆放、花盆的安全工作,若造成损失责任自负。</p>
<p style="text-indent:2em;">3、乙方必须按时缴纳房租,否则视为乙方违约。协议终止。</p>
<p style="text-indent:2em;">
4、乙方应遵守居住区内各项规章制度,按时缴纳水、电、气、光纤、电话、物业管理等费用。乙方交保证金给甲方,乙方退房时交清水,电,气,光纤和物业管理等费用及屋内设施家具、家电无损坏,下水管道,厕所无堵漏。甲方如数退还保证金。
</p>
<p style="text-indent:2em;">5、甲方保证该房屋无产权纠纷。如遇拆迁,乙方无条件搬出,已交租金甲方按未满天数退还。</p>
<p style="text-indent:2em;">四、本合同一式两份,甲乙双方各存一份,自双方签字之日起生效。</p>
<p><br/></p>
<p style="text-indent:2em;">水费:<span class="underline">{$data.water_money}</span>元/人,燃气:<span
class="underline">{$data.gas_money}</span>元/人</p>
<p><br/></p>
<p style="text-indent:2em;">
甲方签名(出租方):&nbsp;{$holder.truename}
</p>
<p><br/></p>
<p style="text-indent:2em;">
乙方签名(承租方):{$tenant.name}
<span id="sign_name"></span>
</p>
<p><br/></p>
<p style="text-indent:2em;">签约日期:{$data.contract_starttime_str|default=''} </p>
</div>
</textarea>
</div>
</div>
<div align="center" style="margin:20px auto; width:320px;">
<canvas id="myCanvas" height="300" width="450" style="border:1px solid #6699cc"></canvas>
<div class="control-ops control">
<button type="button" class="layui-btn layui-bg-red" onclick="javascript:clearArea();return false;">清空画板
</button>
<button type="button" class="saveimg layui-btn" onclick="javascript:saveImageInfo();return false;">确认
</button>
</div>
<div class="saveimgs"></div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-bg-blue" lay-submit="" lay-filter="demo1">支付完成后请点击提交</button>
</div>
</div>
</form>
</div>
<!--电子签名-->
<script type="text/javascript">
var mousePressed = false;
var lastX, lastY;
var ctx = document.getElementById('myCanvas').getContext("2d");
var c = document.getElementById("myCanvas");
// console.log(c)
// console.log(c2)
var control = document.getElementsByClassName("control")[0];
var saveimgs = document.getElementsByClassName("saveimgs")[0];
window.onload = function () {
InitThis();
}
function saveImageInfo() {
var image = c.toDataURL("image/png");
var ctximg = document.createElement("span");
ctximg.innerHTML = "<input type='hidden' value='" + image + "' name='sign_name' /><img src='" + image + "' alt='from canvas'/>";
if (saveimgs.getElementsByTagName('span').length >= 1) {
var span_old = saveimgs.getElementsByTagName("span")[0];
saveimgs.replaceChild(ctximg, span_old)
}
else {
saveimgs.appendChild(ctximg);
}
// console.log(image)
}
var selected1, selected2;
function aaa() {
var sel = document.getElementById('selWidth');
var value = sel.selectedIndex;
return selected1 = sel[value].value;
}
function aaa2() {
var sel2 = document.getElementById('selColor');
var value = sel2.selectedIndex;
return selected2 = sel2[value].value;
}
function InitThis() {
// 触摸屏
c.addEventListener('touchstart', function (event) {
console.log(1)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
mousePressed = true;
Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, false);
}
}, false);
c.addEventListener('touchmove', function (event) {
console.log(2)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
if (mousePressed) {
Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, true);
}
}
}, false);
c.addEventListener('touchend', function (event) {
console.log(3)
if (event.targetTouches.length == 1) {
event.preventDefault();// 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要
// var touch = event.targetTouches[0];
mousePressed = false;
}
}, false);
/*c.addEventListener('touchcancel', function (event) {
console.log(4)
mousePressed = false;
},false);*/
// 鼠标
c.onmousedown = function (event) {
mousePressed = true;
Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, false);
};
c.onmousemove = function (event) {
if (mousePressed) {
Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, true);
}
};
c.onmouseup = function (event) {
mousePressed = false;
};
}
function Draw(x, y, isDown) {
if (isDown) {
ctx.beginPath();
ctx.strokeStyle = selected2;
ctx.lineWidth = 5;
ctx.lineJoin = "round";
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
}
lastX = x;
lastY = y;
}
function clearArea() {
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// 清除签名图片
if (saveimgs.getElementsByTagName('span').length >= 1) {
var clearImg = saveimgs.getElementsByTagName('span')[0];
saveimgs.removeChild(clearImg);
}
}
</script>
<!--电子签名-->
<script src="/static/plugs/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="/static/plugs/wangedit/js/lib/zepto.js"></script>
<script type="text/javascript" src="/static/plugs/wangedit/js/lib/zepto.touch.js"></script>
<script type="text/javascript" src="/static/plugs/wangedit/js/wangEditor-mobile.js"></script>
<script type="text/javascript">
$(function () {
// 全局配置
// ___E.config.menus = ['bold', 'color', 'quote'];
// 生成编辑器
var editor = new ___E('textarea1');
// 自定义配置
editor.config.uploadImgUrl = '/upload';
// editor.config.menus = ['bold', 'quote', 'list','img'];
// 初始化
editor.init();
console.log(editor.$txt);
});
</script>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
<script>
layui.use(['form', 'layedit', 'laydate'], function () {
var form = layui.form
, layer = layui.layer;
//监听提交
form.on('submit(demo1)', function (data) {
if (data.field.pay_type == undefined) {
layer.alert('请选择支付方式');
return false;
}
if (data.field.sign_name == undefined) {
layer.alert('请查看合同内容,并手写签名后确认!');
return false;
}
});
});
</script>
</body>
</html>

14
application/index/view/upload/index.html

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index/upload/plupload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

64
application/service/controller/Config.php

@ -0,0 +1,64 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\controller;
use library\Controller;
/**
* 开放平台参数配置
* Class Config
* @package app\service\controller
*/
class Config extends Controller
{
/**
* 定义当前操作表名
* @var string
*/
public $table = 'WechatServiceConfig';
/**
* 开放平台配置
* @auth true
* @menu true
*/
public function index()
{
$this->applyCsrfToken('save');
$this->title = '开放平台配置';
$this->fetch();
}
/**
* 保存参数数据
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function save()
{
$this->applyCsrfToken('save');
if ($this->request->post()) {
$post = $this->request->post();
foreach ($post as $k => $v) sysconf($k, $v);
$this->success('开放平台参数修改成功!');
} else {
$this->error('开放平台参数修改失败!');
}
}
}

164
application/service/controller/Fans.php

@ -0,0 +1,164 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\controller;
use app\admin\service\QueueService;
use app\service\service\WechatService;
use app\service\queue\WechatQueue;
use library\Controller;
use think\Db;
use think\exception\HttpResponseException;
/**
* 微信粉丝管理
* Class Fans
* @package app\wechat\controller
*/
class Fans extends Controller
{
protected $appid = '';
/**
* 绑定数据表
* @var string
*/
protected $table = 'WechatFans';
/**
* 初始化函数
* Fans constructor.
*/
public function __construct()
{
parent::__construct();
$this->appid = input('appid', session('current_appid'));
if (empty($this->appid)) {
$this->appid = Db::name('WechatServiceConfig')->value('authorizer_appid');
}
if (empty($this->appid)) {
$this->fetch('/not-auth');
} else {
session('current_appid', $this->appid);
}
if ($this->request->isGet()) {
$this->where = ['status' => '1', 'service_type' => '2', 'is_deleted' => '0'];
$this->wechats = Db::name('WechatServiceConfig')->where($this->where)->order('id desc')->column('authorizer_appid,nick_name');
}
}
/**
* 微信粉丝管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '微信粉丝管理';
$query = $this->_query($this->table)->like('nickname')->equal('subscribe,is_black');
$query->dateBetween('subscribe_at')->where(['appid' => $this->appid])->order('subscribe_time desc')->page();
}
/**
* 列表数据处理
* @param array $data
*/
protected function _index_page_filter(array &$data)
{
$tags = Db::name('WechatFansTags')->column('id,name');
foreach ($data as &$user) {
$user['tags'] = [];
foreach (explode(',', $user['tagid_list']) as $tagid) {
if (isset($tags[$tagid])) $user['tags'][] = $tags[$tagid];
}
}
}
/**
* 批量拉黑粉丝
* @auth true
*/
public function setBlack()
{
$this->applyCsrfToken();
try {
foreach (array_chunk(explode(',', $this->request->post('openid')), 20) as $openids) {
WechatService::WeChatUser($this->appid)->batchBlackList($openids);
Db::name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => '1']);
}
$this->success('拉黑粉丝信息成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("拉黑粉丝信息失败,请稍候再试!{$e->getMessage()}");
}
}
/**
* 取消拉黑粉丝
* @auth true
*/
public function delBlack()
{
try {
$this->applyCsrfToken();
foreach (array_chunk(explode(',', $this->request->post('openid')), 20) as $openids) {
WechatService::WeChatUser($this->appid)->batchUnblackList($openids);
Db::name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => '0']);
}
$this->success('取消拉黑粉丝信息成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("取消拉黑粉丝信息失败,请稍候再试!{$e->getMessage()}");
}
}
/**
* 同步粉丝列表
* @auth true
*/
public function sync()
{
try {
sysoplog('微信管理', "创建微信[{$this->appid}]粉丝同步任务");
QueueService::add("同步[{$this->appid}]粉丝列表", WechatQueue::URI, 0, ['appid' => $this->appid], 0);
$this->success('创建同步粉丝任务成功,需要时间来完成。<br>请到系统任务管理查看进度!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("创建同步粉丝任务失败,请稍候再试!<br> {$e->getMessage()}");
}
}
/**
* 删除粉丝信息
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
$this->applyCsrfToken();
$this->_delete($this->table);
}
}

159
application/service/controller/Index.php

@ -0,0 +1,159 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\controller;
use app\service\service\BuildService;
use app\service\service\WechatService;
use library\Controller;
use think\Db;
/**
* 公众授权管理
* @package app\service\controller
*/
class Index extends Controller
{
/**
* 绑定数据表
* @var string
*/
public $table = 'WechatServiceConfig';
/**
* 公众授权管理
* @auth true
* @menu true
* @return string
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index()
{
$this->applyCsrfToken();
$this->title = '公众授权管理';
$query = $this->_query($this->table)->like('authorizer_appid,nick_name,principal_name');
$query = $query->equal('service_type,status')->dateBetween('create_at');
$query->where(['is_deleted' => '0'])->order('id desc')->page();
}
/**
* 清理调用次数
* @auth true
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function clearQuota()
{
$appid = input('appid');
$result = WechatService::WeChatLimit($appid)->clearQuota();
if (empty($result['errcode']) && $result['errmsg'] === 'ok') {
$this->success('接口调用次数清零成功!');
} elseif (isset($result['errmsg'])) {
$this->error('接口调用次数清零失败,请稍候再试!' . $result['errmsg']);
} else {
$this->error('接口调用次数清零失败,请稍候再试!');
}
}
/**
* 同步指定授权公众号
* @auth true
*/
public function sync()
{
try {
$appid = $this->request->get('appid');
$where = ['authorizer_appid' => $appid, 'is_deleted' => '0', 'status' => '1'];
$author = Db::name('WechatServiceConfig')->where($where)->find();
empty($author) && $this->error('无效的授权信息,请同步其它公众号!');
$data = BuildService::filter(WechatService::service()->getAuthorizerInfo($appid));
$data['authorizer_appid'] = $appid;
$where = ['authorizer_appid' => $data['authorizer_appid']];
$appkey = Db::name('WechatServiceConfig')->where($where)->value('appkey');
if (empty($appkey)) $data['appkey'] = md5(uniqid('', true));
if (data_save('WechatServiceConfig', $data, 'authorizer_appid')) {
$this->success('更新公众号授权信息成功!', '');
}
} catch (\think\exception\HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("获取授权信息失败,请稍候再试!<br>{$e->getMessage()}");
}
}
/**
* 同步所有授权公众号
* @auth true
*/
public function syncall()
{
try {
$wechat = WechatService::service();
$result = $wechat->getAuthorizerList();
foreach ($result['list'] as $item) if (!empty($item['refresh_token']) && !empty($item['auth_time'])) {
$data = BuildService::filter($wechat->getAuthorizerInfo($item['authorizer_appid']));
$data['is_deleted'] = '0';
$data['authorizer_appid'] = $item['authorizer_appid'];
$data['authorizer_refresh_token'] = $item['refresh_token'];
$data['create_at'] = date('Y-m-d H:i:s', $item['auth_time']);
$where = ['authorizer_appid' => $data['authorizer_appid']];
$appkey = Db::name('WechatServiceConfig')->where($where)->value('appkey');
if (empty($appkey)) $data['appkey'] = md5(uniqid('', true));
if (!data_save('WechatServiceConfig', $data, 'authorizer_appid')) {
$this->error('获取授权信息失败,请稍候再试!', '');
}
}
$this->success('同步所有授权信息成功!', '');
} catch (\think\exception\HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
$this->error("同步授权失败,请稍候再试!<br>{$e->getMessage()}");
}
}
/**
* 删除公众号授权
* @auth true
*/
public function remove()
{
$this->applyCsrfToken();
$this->_delete($this->table);
}
/**
* 禁用公众号授权
* @auth true
*/
public function forbid()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用公众号授权
* @auth true
*/
public function resume()
{
$this->applyCsrfToken();
$this->_save($this->table, ['status' => '1']);
}
}

155
application/service/controller/api/Client.php

@ -0,0 +1,155 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\controller\api;
use app\service\service\WechatService;
use think\Controller;
use think\Db;
/**
* 获取微信SDK实例对象
* Class Instance
* @package app\wechat\controller
*/
class Client extends Controller
{
/**
* 当前配置
* @var string
*/
protected $config = [];
/**
* 当前APPID
* @var string
*/
protected $appid = '';
/**
* 接口实例名称
* @var string
*/
protected $name = '';
/**
* 接口类型
* @var string
*/
protected $type = '';
/**
* 错误消息
* @var string
*/
protected $message = '';
/**
* 启动Yar接口服务
* @param string $param AppName-AppId-AppKey
* @return string
*/
public function yar($param)
{
try {
$instance = $this->create($param);
$service = new \Yar_Server(empty($instance) ? $this : $instance);
$service->handle();
} catch (\Exception $e) {
return $e->getMessage();
}
}
/**
* 启动SOAP接口服务
* @param string $param AppName-AppId-AppKey
* @return string
*/
public function soap($param)
{
try {
$instance = $this->create($param);
$service = new \SoapServer(null, ['uri' => strtolower($this->name)]);
$service->setObject(empty($instance) ? $this : $instance);
$service->handle();
} catch (\Exception $e) {
return $e->getMessage();
}
}
/**
* 创建接口服务
* @param string $token
* @return \WeChat\Oauth|\WeChat\Pay|\WeChat\Receive|\WeChat\Script|\WeChat\User|\WeOpen\Service
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\Exception
*/
private function create($token)
{
if ($this->auth($token)) {
$weminiClassName = 'Account,Basic,Code,Domain,Tester,User,Crypt,Plugs,Poi,Qrcode,Template,Total';
$wechatClassName = 'Card,Custom,Limit,Media,Menu,Oauth,Pay,Product,Qrcode,Receive,Scan,Script,Shake,Tags,Template,User,Wifi';
if ($this->type === 'wechat' && stripos($wechatClassName, $this->name) !== false) {
$instance = WechatService::instance($this->name, $this->appid, 'WeChat');
} elseif ($this->type === 'wemini' && stripos($weminiClassName, $this->name) !== false) {
$instance = WechatService::instance($this->name, $this->appid, 'WeMini');
} elseif (stripos('Service,MiniApp', $this->name) !== false) {
$instance = WechatService::instance($this->name, $this->appid, 'WeOpen');
} elseif (stripos('Wechat,Config,Handler', $this->name) !== false) {
$className = "\\app\\service\\handler\\WechatHandler";
$instance = new $className($this->config);
}
if (!empty($instance)) return $instance;
}
throw new \think\Exception($this->message);
}
/**
* 加载微信实例对象
* @param string $token 数据格式 name|appid|appkey
* @return bool
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
private function auth($token = '')
{
list($this->name, $this->appid, $appkey, $this->type) = explode('-', $token . '---');
if (empty($this->name) || empty($this->appid) || empty($appkey)) {
$this->message = '缺少必要的参数AppId或AppKey';
return false;
}
$where = ['authorizer_appid' => $this->appid, 'status' => '1', 'is_deleted' => '0'];
$this->config = Db::name('WechatServiceConfig')->where($where)->find();
if (empty($this->config)) {
$this->message = '无效的微信绑定对象';
return false;
}
if (strtolower($this->config['appkey']) !== strtolower($appkey)) {
$this->message = '授权AppId与AppKey不匹配';
return false;
}
$this->message = '';
$this->name = ucfirst(strtolower($this->name));
$this->type = strtolower(empty($this->type) ? 'WeChat' : $this->type);
Db::name('WechatServiceConfig')->where($where)->setInc('total', 1);
return true;
}
}

183
application/service/controller/api/Push.php

@ -0,0 +1,183 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\controller\api;
use app\service\service\BuildService;
use app\service\service\WechatService;
use library\Controller;
use think\Db;
/**
* 微信推送事件处理
*
* @author Anyon <zoujingli@qq.com>
* @date 2016/10/18 12:38
*/
class Push extends Controller
{
/**
* 微信API推送事件处理
* @param string $appid
* @return string
* @throws \think\Exception
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function notify($appid)
{
if (in_array($appid, ['wx570bc396a51b8ff8', 'wxd101a85aa106f53e'])) {
# 全网发布接口测试
return \app\service\handler\PublishHandler::handler($appid);
} else {
# 接口类正常服务
return \app\service\handler\ReceiveHandler::handler($appid);
}
}
/**
* 一、处理服务推送Ticket
* 二、处理取消公众号授权
* @return string
* @throws \think\Exception
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\exception\PDOException
*/
public function ticket()
{
try {
$server = WechatService::service();
if (!($data = $server->getComonentTicket())) {
return "Ticket event handling failed.";
}
} catch (\Exception $e) {
return "Ticket event handling failed, {$e->getMessage()}";
}
if (!empty($data['AuthorizerAppid']) && isset($data['InfoType'])) {
# 授权成功通知
if ($data['InfoType'] === 'authorized') {
Db::name('WechatServiceConfig')->where(['authorizer_appid' => $data['AuthorizerAppid']])->update(['is_deleted' => '0']);
}
# 接收取消授权服务事件
if ($data['InfoType'] === 'unauthorized') {
Db::name('WechatServiceConfig')->where(['authorizer_appid' => $data['AuthorizerAppid']])->update(['is_deleted' => '1']);
}
# 授权更新通知
if ($data['InfoType'] === 'updateauthorized') {
$_GET['auth_code'] = $data['PreAuthCode'];
$this->applyAuth($server);
}
}
return 'success';
}
/**
* 网页授权
* @throws \think\Exception
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function oauth()
{
list($mode, $appid, $enurl, $sessid) = [
$this->request->get('mode'), $this->request->get('state'),
$this->request->get('enurl'), $this->request->get('sessid'),
];
$service = WechatService::service();
$result = $service->getOauthAccessToken($appid);
if (empty($result['openid'])) throw new \think\Exception('网页授权失败, 无法进一步操作!');
cache("{$appid}_{$sessid}_openid", $result['openid'], 3600);
if (!empty($mode)) {
$wechat = new \WeChat\Oauth($service->getConfig($appid));
$fans = $wechat->getUserInfo($result['access_token'], $result['openid']);
if (empty($fans)) throw new \think\Exception('网页授权信息获取失败, 无法进一步操作!');
cache("{$appid}_{$sessid}_fans", $fans, 3600);
}
redirect(decode($enurl), [], 301)->send();
}
/**
* 跳转到微信服务授权页面
* @param string $redirect
* @return string
* @throws \think\Exception
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\exception\PDOException
*/
public function auth($redirect = '')
{
$fromRedirect = decode($redirect);
if (empty($redirect) || empty($fromRedirect)) {
return '请传入回跳Redirect参数 ( 请使用ENCODE加密 )';
}
# 预授权码不为空,则表示可以进行授权处理
$service = WechatService::service();
if (($auth_code = $this->request->get('auth_code'))) {
return $this->applyAuth($service, $fromRedirect);
}
# 生成微信授权链接,使用刷新跳转到授权网页
$url = url("@service/api.push/auth/{$redirect}", false, true, true);
if (($redirect = $service->getAuthRedirect($url))) {
ob_clean();
header("Refresh:0;url={$redirect}");
return "<script>window.location.href='{$redirect}';</script><a href='{$redirect}'>跳转中...</a>";
}
# 生成微信授权链接失败
return "<h2>Failed to create authorization. Please return to try again.</h2>";
}
/**
* 公众号授权绑定数据处理
* @param \WeOpen\Service $service
* @param string|null $redirect 授权成功回跳地址
* @return string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function applyAuth($service, $redirect = null)
{
// 通过授权code换取公众号信息
$result = $service->getQueryAuthorizerInfo();
if (empty($result['authorizer_appid'])) {
return "接收微信第三方平台授权失败! ";
}
// 重新通过接口查询公众号参数
if (!($update = array_merge($result, $service->getAuthorizerInfo($result['authorizer_appid'])))) {
return '获取授权数据失败, 请稍候再试!';
}
// 生成公众号授权参数
$update = array_merge(BuildService::filter($update), [
'status' => '1', 'is_deleted' => '0', 'expires_in' => time() + 7000, 'create_at' => date('y-m-d H:i:s'),
]);
// 微信接口APPKEY处理与更新
$config = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $result['authorizer_appid']])->find();
$update['appkey'] = empty($config['appkey']) ? md5(uniqid('', true)) : $config['appkey'];
data_save('WechatServiceConfig', $update, 'authorizer_appid');
if (!empty($redirect)) { // 带上appid与appkey跳转到应用
$split = stripos($redirect, '?') > 0 ? '&' : '?';
$realurl = preg_replace(['/appid=\w+/i', '/appkey=\w+/i', '/(\?\&)$/i'], ['', '', ''], $redirect);
return redirect("{$realurl}{$split}appid={$update['authorizer_appid']}&appkey={$update['appkey']}");
}
}
}

69
application/service/handler/PublishHandler.php

@ -0,0 +1,69 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\handler;
use app\service\service\WechatService;
/**
* 第三方平台测试上线
*
* @author Anyon <zoujingli@qq.com>
* @date 2016/10/27 14:14
*/
class PublishHandler
{
/**
* 当前微信APPID
* @var string
*/
protected static $appid;
/**
* 事件初始化
* @param string $appid
* @return string
* @throws \WeChat\Exceptions\InvalidDecryptException
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public static function handler($appid)
{
try {
$wechat = WechatService::WeChatReceive($appid);
} catch (\Exception $e) {
return "Wechat message handling failed, {$e->getMessage()}";
}
/* 分别执行对应类型的操作 */
switch (strtolower($wechat->getMsgType())) {
case 'text':
$receive = $wechat->getReceive();
if ($receive['Content'] === 'TESTCOMPONENT_MSG_TYPE_TEXT') {
return $wechat->text('TESTCOMPONENT_MSG_TYPE_TEXT_callback')->reply([], true);
} else {
$key = str_replace("QUERY_AUTH_CODE:", '', $receive['Content']);
WechatService::service()->getQueryAuthorizerInfo($key);
return $wechat->text("{$key}_from_api")->reply([], true);
}
case 'event':
$receive = $wechat->getReceive();
return $wechat->text("{$receive['Event']}from_callback")->reply([], true);
default:
return 'success';
}
}
}

69
application/service/handler/ReceiveHandler.php

@ -0,0 +1,69 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\handler;
use app\service\service\WechatService;
use think\Db;
/**
* 微信推送消息处理
*
* @author Anyon <zoujingli@qq.com>
* @date 2016/10/27 14:14
*/
class ReceiveHandler
{
/**
* 事件初始化
* @param string $appid
* @return string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\Exception
*/
public static function handler($appid)
{
try {
$wechat = WechatService::WeChatReceive($appid);
} catch (\Exception $e) {
return "Wechat message handling failed, {$e->getMessage()}";
}
// 验证微信配置信息
$config = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $appid])->find();
if (empty($config) || empty($config['appuri'])) {
\think\facade\Log::error(($message = "微信{$appid}授权配置验证无效"));
return $message;
}
try {
list($data, $openid) = [$wechat->getReceive(), $wechat->getOpenid()];
if (isset($data['EventKey']) && is_object($data['EventKey'])) $data['EventKey'] = (array)$data['EventKey'];
$input = ['openid' => $openid, 'appid' => $appid, 'receive' => serialize($data), 'encrypt' => intval($wechat->isEncrypt())];
if (is_string($result = http_post($config['appuri'], $input, ['timeout' => 30]))) {
if (is_array($json = json_decode($result, true))) {
return $wechat->reply($json, true, $wechat->isEncrypt());
} else {
return $result;
}
}
} catch (\Exception $e) {
\think\facade\Log::error("微信{$appid}接口调用异常,{$e->getMessage()}");
}
return 'success';
}
}

161
application/service/handler/WechatHandler.php

@ -0,0 +1,161 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\handler;
use app\service\service\WechatService as WechatLogic;
use think\Db;
/**
* 微信网页授权接口
* Class WechatHandler
* @package app\wechat\handler
* @author Anyon <zoujingli@qq.com>
*/
class WechatHandler
{
/**
* 当前微信APPID
* @var string
*/
protected $appid;
/**
* 当前微信配置
* @var array
*/
protected $config;
/**
* 错误消息
* @var string
*/
protected $message;
/**
* Wechat constructor.
* @param array $config
*/
public function __construct($config = [])
{
$this->config = $config;
$this->appid = isset($config['authorizer_appid']) ? $config['authorizer_appid'] : '';
}
/**
* 检查微信配置服务初始化状态
* @return boolean
* @throws \think\Exception
*/
private function checkInit()
{
if (!empty($this->config)) return true;
throw new \think\Exception('Wechat Please bind Wechat first');
}
/**
* 获取当前公众号配置
* @return array|boolean
* @throws \think\Exception
*/
public function getConfig()
{
$this->checkInit();
$info = Db::name('WechatServiceConfig')->where(['authorizer_appid' => $this->appid])->find();
if (empty($info)) return false;
if (isset($info['id'])) unset($info['id']);
return $info;
}
/**
* 设置微信接口通知URL地址
* @param string $notifyUri 接口通知URL地址
* @return boolean
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function setApiNotifyUri($notifyUri)
{
$this->checkInit();
if (empty($notifyUri)) throw new \think\Exception('请传入微信通知URL');
list($where, $data) = [['authorizer_appid' => $this->appid], ['appuri' => $notifyUri]];
return Db::name('WechatServiceConfig')->where($where)->update($data) !== false;
}
/**
* 更新接口Appkey(成功返回新的Appkey)
* @return bool|string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function updateApiAppkey()
{
$this->checkInit();
$data = ['appkey' => md5(uniqid())];
Db::name('WechatServiceConfig')->where(['authorizer_appid' => $this->appid])->update($data);
return $data['appkey'];
}
/**
* 获取公众号的配置参数
* @param string $name 参数名称
* @return array|string
* @throws \think\Exception
*/
public function config($name = null)
{
$this->checkInit();
return WechatLogic::WeChatScript($this->appid)->config->get($name);
}
/**
* 微信网页授权
* @param string $sessid 当前会话id(可用session_id()获取)
* @param string $selfUrl 当前会话URL地址(需包含域名的完整URL地址)
* @param int $fullMode 网页授权模式(0静默模式,1高级授权)
* @return array|bool
* @throws \think\Exception
*/
public function oauth($sessid, $selfUrl, $fullMode = 0)
{
$this->checkInit();
$fans = cache("{$this->appid}_{$sessid}_fans");
$openid = cache("{$this->appid}_{$sessid}_openid");
if (!empty($openid) && (empty($fullMode) || !empty($fans))) {
return ['openid' => $openid, 'fans' => $fans, 'url' => ''];
}
$service = WechatLogic::service();
$mode = empty($fullMode) ? 'snsapi_base' : 'snsapi_userinfo';
$url = url('@service/api.push/oauth', '', true, true);
$params = ['mode' => $fullMode, 'sessid' => $sessid, 'enurl' => encode($selfUrl)];
$authurl = $service->getOauthRedirect($this->appid, $url . '?' . http_build_query($params), $mode);
return ['openid' => $openid, 'fans' => $fans, 'url' => $authurl];
}
/**
* 微信网页JS签名
* @param string $url 当前会话URL地址(需包含域名的完整URL地址)
* @return array|boolean
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\Exception
*/
public function jsSign($url)
{
$this->checkInit();
return WechatLogic::WeChatScript($this->appid)->getJsSign($url);
}
}

82
application/service/queue/WechatQueue.php

@ -0,0 +1,82 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\queue;
use app\admin\queue\JobsQueue;
use app\service\service\WechatService;
use app\wechat\service\FansService;
use think\Db;
/**
* Class Jobs
* @package app\wechat
*/
class WechatQueue extends JobsQueue
{
/**
* 当前任务URI
*/
const URI = self::class;
/**
* 当前操作APPID
* @var string
*/
protected $appid;
/**
* 执行任务
* @return boolean
*/
public function execute()
{
try {
$this->appid = $this->data['appid'];
$wechat = WechatService::WeChatUser($this->appid);
$next = ''; // 获取远程粉丝
$this->output->writeln('Start synchronizing fans from the Wechat server');
while (is_array($result = $wechat->getUserList($next)) && !empty($result['data']['openid'])) {
foreach (array_chunk($result['data']['openid'], 100) as $chunk)
if (is_array($list = $wechat->getBatchUserInfo($chunk)) && !empty($list['user_info_list']))
foreach ($list['user_info_list'] as $user) FansService::set($user, $this->appid);
if (in_array($result['next_openid'], $result['data']['openid'])) break;
$next = $result['next_openid'];
}
$next = ''; // 同步粉丝黑名单
$this->output->writeln('Start synchronizing black from the Wechat server');
while (is_array($result = $wechat->getBlackList($next)) && !empty($result['data']['openid'])) {
foreach (array_chunk($result['data']['openid'], 100) as $chunk) {
$where = [['is_black', 'eq', '0'], ['openid', 'in', $chunk]];
Db::name('WechatFans')->where($where)->update(['is_black' => '1']);
}
if (in_array($result['next_openid'], $result['data']['openid'])) break;
$next = $result['next_openid'];
}
// 同步粉丝标签列表
$this->output->writeln('Start synchronizing tags from the Wechat server');
if (is_array($list = WechatService::WeChatTags($this->appid)->getTags()) && !empty($list['tags'])) {
foreach ($list['tags'] as &$tag) $tag['appid'] = $this->appid;
Db::name('WechatFansTags')->where('1=1')->delete();
Db::name('WechatFansTags')->insertAll($list['tags']);
}
return true;
} catch (\Exception $e) {
$this->statusDesc = $e->getMessage();
return false;
}
}
}

53
application/service/service/BuildService.php

@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\service;
/**
* 授权数据处理
* Class Build
* @package app\service\service
*/
class BuildService
{
/**
* 授权数据过滤转换处理
* @param array $info
* @return mixed
*/
public static function filter(array $info)
{
if (isset($info['func_info'])) $info['func_info'] = join(',', array_map(function ($tmp) {
return $tmp['funcscope_category']['id'];
}, $info['func_info']));
$info['verify_type_info'] = join(',', $info['verify_type_info']);
$info['service_type_info'] = join(',', $info['service_type_info']);
$info['business_info'] = json_encode($info['business_info'], JSON_UNESCAPED_UNICODE);
// 微信类型: 0 代表订阅号, 2 代表服务号, 3 代表小程序
$info['service_type'] = intval($info['service_type_info']) === 2 ? 2 : 0;
if (!empty($info['MiniProgramInfo'])) {
// 微信类型: 0 代表订阅号, 2 代表服务号, 3 代表小程序
$info['service_type'] = 3;
// 小程序信息
$info['miniprograminfo'] = json_encode($info['MiniProgramInfo'], JSON_UNESCAPED_UNICODE);
}
unset($info['MiniProgramInfo']);
// 微信认证: -1 代表未认证, 0 代表微信认证
$info['verify_type'] = intval($info['verify_type_info']) !== 0 ? -1 : 0;
return $info;
}
}

151
application/service/service/WechatService.php

@ -0,0 +1,151 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\service\service;
use think\Db;
/**
* 微信数据服务
* Class WechatService
* @package app\service\service
* @method \WeChat\Card WeChatCard($appid) static 微信卡券管理
* @method \WeChat\Custom WeChatCustom($appid) static 微信客服消息
* @method \WeChat\Limit WeChatLimit($appid) static 接口调用频次限制
* @method \WeChat\Media WeChatMedia($appid) static 微信素材管理
* @method \WeChat\Menu WeChatMenu($appid) static 微信菜单管理
* @method \WeChat\Oauth WeChatOauth($appid) static 微信网页授权
* @method \WeChat\Pay WeChatPay($appid) static 微信支付商户
* @method \WeChat\Product WeChatProduct($appid) static 微信商店管理
* @method \WeChat\Qrcode WeChatQrcode($appid) static 微信二维码管理
* @method \WeChat\Receive WeChatReceive($appid) static 微信推送管理
* @method \WeChat\Scan WeChatScan($appid) static 微信扫一扫接入管理
* @method \WeChat\Script WeChatScript($appid) static 微信前端支持
* @method \WeChat\Shake WeChatShake($appid) static 微信揺一揺周边
* @method \WeChat\Tags WeChatTags($appid) static 微信用户标签管理
* @method \WeChat\Template WeChatTemplate($appid) static 微信模板消息
* @method \WeChat\User WeChatUser($appid) static 微信粉丝管理
* @method \WeChat\Wifi WeChatWifi($appid) static 微信门店WIFI管理
*
* ----- WeMini -----
* @method \WeMini\Account WeMiniAccount($appid) static 小程序账号管理
* @method \WeMini\Basic WeMiniBasic($appid) static 小程序基础信息设置
* @method \WeMini\Code WeMiniCode($appid) static 小程序代码管理
* @method \WeMini\Domain WeMiniDomain($appid) static 小程序域名管理
* @method \WeMini\Tester WeMinitester($appid) static 小程序成员管理
* @method \WeMini\User WeMiniUser($appid) static 小程序帐号管理
* --------------------
* @method \WeMini\Crypt WeMiniCrypt($appid) static 小程序数据加密处理
* @method \WeMini\Plugs WeMiniPlugs($appid) static 小程序插件管理
* @method \WeMini\Poi WeMiniPoi($appid) static 小程序地址管理
* @method \WeMini\Qrcode WeMiniQrcode($appid) static 小程序二维码管理
* @method \WeMini\Template WeMiniTemplate($appid) static 小程序模板消息支持
* @method \WeMini\Total WeMiniTotal($appid) static 小程序数据接口
*
* ----- WePay -----
* @method \WePay\Bill WePayBill($appid) static 微信商户账单及评论
* @method \WePay\Order WePayOrder($appid) static 微信商户订单
* @method \WePay\Refund WePayRefund($appid) static 微信商户退款
* @method \WePay\Coupon WePayCoupon($appid) static 微信商户代金券
* @method \WePay\Redpack WePayRedpack($appid) static 微信红包支持
* @method \WePay\Transfers WePayTransfers($appid) static 微信商户打款到零钱
* @method \WePay\TransfersBank WePayTransfersBank($appid) static 微信商户打款到银行卡
*
* ----- WeOpen -----
* @method \WeOpen\Login login() static 第三方微信登录
* @method \WeOpen\Service service() static 第三方服务
*
* ----- ThinkService -----
* @method mixed wechat() static 第三方微信工具
* @method mixed config() static 第三方配置工具
*/
class WechatService
{
/**
* 接口类型模式
* @var string
*/
private static $type = 'WeChat';
/**
* 实例微信对象
* @param string $name
* @param string $appid 授权公众号APPID
* @param string $type 将要获取SDK类型
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function instance($name, $appid = '', $type = null)
{
$config = [
'cache_path' => env('runtime_path') . 'wechat',
'component_appid' => sysconf('component_appid'),
'component_token' => sysconf('component_token'),
'component_appsecret' => sysconf('component_appsecret'),
'component_encodingaeskey' => sysconf('component_encodingaeskey'),
];
// 注册授权公众号 AccessToken 处理
$config['GetAccessTokenCallback'] = function ($authorizerAppid) use ($config) {
$where = ['authorizer_appid' => $authorizerAppid];
if (!($refreshToken = Db::name('WechatServiceConfig')->where($where)->value('authorizer_refresh_token'))) {
throw new \think\Exception('The WeChat information is not configured.', '404');
}
$open = new \WeOpen\MiniApp($config);
$result = $open->refreshAccessToken($authorizerAppid, $refreshToken);
if (empty($result['authorizer_access_token']) || empty($result['authorizer_refresh_token'])) {
throw new \think\Exception($result['errmsg'], '0');
}
Db::name('WechatServiceConfig')->where($where)->update([
'authorizer_access_token' => $result['authorizer_access_token'],
'authorizer_refresh_token' => $result['authorizer_refresh_token'],
]);
return $result['authorizer_access_token'];
};
$app = new \WeOpen\MiniApp($config);
if (in_array(strtolower($name), ['service', 'miniapp'])) {
return $app;
}
if (!in_array($type, ['WeChat', 'WeMini'])) {
$type = self::$type;
}
return $app->instance($name, $appid, $type);
}
/**
* 静态初始化对象
* @param string $name
* @param array $arguments
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function __callStatic($name, $arguments)
{
if (substr($name, 0, 6) === 'WeMini') {
self::$type = 'WeMini';
$name = substr($name, 6);
} elseif (substr($name, 0, 6) === 'WeChat') {
self::$type = 'WeChat';
$name = substr($name, 6);
} elseif (substr($name, 0, 5) === 'WePay') {
self::$type = 'WePay';
$name = substr($name, 5);
}
return self::instance($name, isset($arguments[0]) ? $arguments[0] : '', self::$type);
}
}

109
application/service/view/config/index.html

@ -0,0 +1,109 @@
{extend name="admin@main"}
{block name="content"}
<div class="relative">
<div class="think-box-shadow border-0 margin-bottom-20">
强烈建议安装 YAR 扩展来实现接口通信,SOAP 不能正常显示接口的异常信息
</div>
<div class="layui-row layui-col-space15">
<div class="layui-col-lg6">
<fieldset class="think-box-shadow">
<legend class="layui-bg-cyan">授权参数</legend>
<form onsubmit="return false;" action="{:url('save')}" data-auto="true" method="post" class='layui-form padding-left-20 padding-right-20' autocomplete="off">
<div class="layui-form-item">
<label class="relative block">
<span class="color-green">开放平台服务 AppID</span>
<input name="component_appid" required pattern="^.{18}$" maxlength="18" placeholder="请输入18位开放平台服务AppID" value="{:sysconf('component_appid')}" class="layui-input">
</label>
<p class="help-block">开放平台服务 AppID,需要在微信开放平台获取</p>
</div>
<div class="layui-form-item">
<label class="relative block">
<span class="color-green">开放平台服务 AppSecret</span>
<input name="component_appsecret" required pattern="^.{32}$" maxlength="32" placeholder="请输入32位开放平台服务AppSecret" value="{:sysconf('component_appsecret')}" class="layui-input">
</label>
<p class="help-block">开放平台服务 AppSecret,需要在微信开放平台获取</p>
</div>
<div class="layui-form-item">
<label class="relative block">
<span class="color-green">开放平台消息校验 Token</span>
<input name="component_token" required placeholder="请输入微信消息校验Token" value="{:sysconf('component_token')}" class="layui-input">
</label>
<p class="help-block">开发者在代替微信接收到消息时,用此 Token 来校验消息</p>
</div>
<div class="layui-form-item">
<label class="relative block">
<span class="color-green">开放平台消息加解密 AesKey</span>
<input name="component_encodingaeskey" required pattern="^.{43}$" maxlength="43" placeholder="请输入43位微信消息加解密Key" value="{:sysconf('component_encodingaeskey')}" class="layui-input">
</label>
<p class="help-block">在代替微信收发消息时使用,必须是长度为43位字母和数字组合的字符串</p>
</div>
<div class="hr-line-dashed"></div>
<div class="text-center padding-bottom-15 margin-bottom-20">
<button class="layui-btn" type="submit">保存配置</button>
</div>
</form>
</fieldset>
</div>
<div class="layui-col-lg6">
<fieldset class="think-box-shadow">
<legend class="layui-bg-cyan">对接信息</legend>
<div class="padding-right-20 padding-left-20">
<div class="layui-form-item">
<p class="color-green">授权发起页域名</p>
<label class="relative block">
<input disabled class="layui-input layui-bg-gray" value="{:request()->host()}">
<a data-copy="{:request()->host()}" class="fa fa-copy right-btn"></a>
</label>
<p class="help-block">从本域名跳转到登录授权页才可以完成登录授权,无需填写域名协议前缀</p>
</div>
<div class="layui-form-item">
<p class="color-green">授权事件接收 URL</p>
<label class="relative block">
<input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.push/ticket','',false,true)}">
<a data-copy="{:url('@service/api.push/ticket','',false,true)}" class="fa fa-copy right-btn"></a>
</label>
<p class="help-block">用于接收取消授权通知、授权成功通知、授权更新通知、接收 TICKET 凭据</p>
</div>
<div class="layui-form-item">
<p class="color-green">微信消息与事件接收 URL</p>
<label class="relative block">
<input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.push/notify/\$APPID\$','',false,true)}">
<a data-copy="{:url('@service/api.push/notify/\$APPID\$','',false,true)}" class="fa fa-copy right-btn"></a>
</label>
<p class="help-block">通过该 URL 接收微信消息和事件推送,$APPID$ 将被替换为微信 AppId</p>
</div>
<div class="layui-form-item">
<p class="color-green">客户端系统 Yar 模块接口</p>
<label class="relative block"><input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.client/yar/PARAM','',false,true)}"></label>
<p class="help-block">客户端 Yar 接口,PARAM 规则 AppName-AppId-AppKey-AppType</p>
</div>
<div class="layui-form-item">
<p class="color-green">客户端系统 Soap 模块接口</p>
<label class="relative block"><input disabled class="layui-input layui-bg-gray" value="{:url('@service/api.client/soap/PARAM','',false,true)}"></label>
<p class="help-block">客户端 Soap 接口,PARAM 规则 AppName-AppId-AppKey-AppType</p>
</div>
</div>
</fieldset>
</div>
</div>
</div>
{/block}
{block name='style'}
<style>
.right-btn {
top: 0;
right: 0;
width: 38px;
height: 38px;
display: inline-block;
position: absolute;
text-align: center;
line-height: 38px;
}
</style>
{/block}

98
application/service/view/fans/index.html

@ -0,0 +1,98 @@
{extend name='admin@main'}
{block name="button"}
{if auth("service/fans/setblack")}
<button data-action='{:url("setblack")}' data-rule="openid#{key}" data-csrf="{:systoken('service/fans/setblack')}" class='layui-btn layui-btn-sm layui-btn-primary'>批量拉黑</button>
{/if}
{if auth("service/fans/delblack")}
<button data-action='{:url("delblack")}' data-rule="openid#{key}" data-csrf="{:systoken('service/fans/delblack')}" class='layui-btn layui-btn-sm layui-btn-primary'>取消拉黑</button>
{/if}
{if auth("service/fans/sync")}
<button data-load='{:url("sync")}' class='layui-btn layui-btn-sm layui-btn-primary'>同步粉丝</button>
{/if}
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='fans/index_search'}
<table class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='list-table-check-td think-checkbox'><input data-auto-none data-check-target='.list-check-box' type='checkbox'></th>
<th width="180px" class='text-left nowrap'>微信昵称</th>
<th width="180px" class="text-left nowrap">粉丝标签</th>
<th width="150px" class='text-left nowrap'>性别语言</th>
<th width="180px" class='text-left nowrap'>关注时间</th>
<th width="80px"></th>
<th></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr>
<td class='list-table-check-td think-checkbox'>
<input class="list-check-box" value='{$vo.openid}' type='checkbox'>
</td>
<td class='text-left nowrap relative layui-elip'>
<img src="{$vo.headimgurl|default=''}" onerror="$(this).remove()" data-tips-image class="inline-block" style="width:40px;height:40px;vertical-align:top;margin-right:5px">
<div class="inline-block">
昵称:{$vo.nickname|default='--'}
<br>
区域:{$vo.country|default='--'} {$vo.province} {$vo.city}
</div>
</td>
<td class="text-left padding-0">
<div style="max-height:60px;overflow:auto">{foreach $vo.tags as $t}<p><span class="layui-badge layui-bg-cyan margin-right-5">{$t|default='--'}</span></p>{/foreach}</div>
</td>
<td class='text-left nowrap'>
性别:{switch name='vo.sex'}{case value='1'}男{/case}{case value='2'}女{/case}{default}未知{/switch}
<br>
语言:{$vo.language|raw}
</td>
<td class='text-left nowrap'>
日期:{$vo.subscribe_at|format_datetime|str_replace=' ','<br>时间:',###|raw}
</td>
<td class='text-center nowrap'>
{eq name='vo.subscribe' value='0'}
<span class="layui-badge">未关注</span>
{else}
<span class="layui-badge layui-bg-green">已关注</span>
{/eq}
<br>
{eq name='vo.is_black' value='0'}
<span class="layui-badge layui-bg-green">未拉黑</span>
{else}
<span class="layui-badge">已拉黑</span>
{/eq}
</td>
<td class="nowrap">
{eq name='vo.is_black' value='0'}
<!--{if auth("service/fans/setblack")}-->
<a class="margin-left-10 layui-btn layui-btn-normal layui-btn-sm" data-action="{:url('setblack')}" data-value="openid#{$vo.openid}" data-csrf="{:systoken('service/fans/setblack')}">拉 黑</a>
<!--{/if}-->
{else}
<!--{if auth("service/fans/delblack")}-->
<a class="margin-left-10 layui-btn layui-btn-normal layui-btn-sm" data-action="{:url('delblack')}" data-value="openid#{$vo.openid}" data-csrf="{:systoken('service/fans/delblack')}">拉 白</a>
<!--{/if}-->
{/eq}
{if auth("service/fans/remove")}
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该粉丝吗?" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('service/fans/remove')}">删 除</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

76
application/service/view/fans/index_search.html

@ -0,0 +1,76 @@
<!-- 表单搜索 开始 -->
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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 class="layui-select" name="appid" lay-search>
<!--{foreach $wechats as $k=>$v}-->
<!--{if $k eq $appid}-->
<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 name="nickname" value="{$Think.get.nickname|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="subscribe">
{foreach [''=>'-- 全部 --','0'=>'显示未关注的粉丝','1'=>'显示已关注的粉丝'] as $k=>$v}
{eq name='Think.get.subscribe' value='$k.""'}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/eq}
{/foreach}
</select>
</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="is_black">
{foreach [''=>'-- 全部 --','0'=>'显示未拉黑的粉丝','1'=>'显示已拉黑的粉丝'] as $k=>$v}
{eq name='Think.get.is_black' value='$k.""'}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/eq}
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">关注时间</label>
<div class="layui-input-inline">
<input name="subscribe_at" value="{$Think.get.subscribe_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>
<script>
window.form.render();
window.laydate.render({range: true, elem: '[name="subscribe_at"]'});
</script>
<!-- 表单搜索 结束 -->

84
application/service/view/index/index.html

@ -0,0 +1,84 @@
{extend name="admin@main"}
{block name="button"}
{if auth("service/index/syncall")}
<button data-load="{:url('syncall')}" class='layui-btn layui-btn-sm layui-btn-primary'>同步授权信息</button>
{/if}
{/block}
{block name="content"}
<div class="think-box-shadow">
{include file='index/index_search'}
<table class="layui-table margin-top-10" lay-skin="line">
{notempty name='list'}
<thead>
<tr>
<th class='text-left nowrap' style="width:390px">接口信息</th>
<th class='text-left nowrap' style="width:120px">服务号信息</th>
<th class='text-left nowrap'></th>
<th class='text-left nowrap'></th>
</tr>
</thead>
{/notempty}
<tbody>
{foreach $list as $key=>$vo}
<tr>
<td class='text-left nowrap'>
<div class="inline-block text-top margin-right-5">
<img onerror="this.src='__ROOT__/static/theme/img/404_icon.png'" style="width:60px;height:60px" data-tips-text="微信头像" data-tips-image src="{$vo.head_img|default=''}">
</div>
<div class="inline-block">
公众号APPID:{$vo.authorizer_appid}&nbsp;&nbsp;&nbsp;&nbsp;调用次数:{$vo.total}<br>
接口授权密钥:{$vo.appkey|default='<span class="color-desc">未生成接口服务密码, 请稍候授权绑定</span>'|raw}<br>
消息推送接口:{$vo.appuri|default='<span class="color-desc">未配置消息推送接口</span>'|raw}
</div>
</td>
<td class='text-left nowrap'>
<div class="inline-block text-top margin-right-5">
<img onerror="this.src='__ROOT__/static/theme/img/404_icon.png'" style="width:60px;height:60px" data-tips-text="微信二维码" data-tips-image src="{$vo.qrcode_url|local_image}">
</div>
<div class="inline-block">
昵称:{$vo.nick_name|default='<span class="color-desc">未获取到公众号昵称</span>'|raw}<br>
公司:{$vo.principal_name|default='<span class="color-desc">未获取到公司名字</span>'|raw}<br>
状态:{if $vo.service_type eq 2}服务号{elseif $vo.service_type eq 3}小程序{else}订阅号{/if} /
{$vo.verify_type == -1 ? '<span class="color-red">未认证</span>' : '<span class="color-green">已认证</span>'} /
{if $vo.status eq 0}<span class="color-red">已禁用</span>{elseif $vo.status eq 1}<span class="color-green">使用中</span>{/if}
</div>
</td>
<td class="text-left nowrap">
账号:{$vo.user_name|default='--'}<br>
日期:{$vo.create_at|format_datetime|str_replace=' ','<br>时间:',###|raw}
</td>
<td class='text-left nowrap'>
{if $vo.status eq 1 and auth("servce/index/forbid")}
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('forbid')}" data-csrf="{:systoken('service/index/forbid')}" data-value="id#{$vo.id};status#0">禁 用</a>
{elseif auth("servce/index/resume")}
<a class="layui-btn layui-btn-sm layui-btn-warm" data-action="{:url('resume')}" data-csrf="{:systoken('service/index/resume')}" data-value="id#{$vo.id};status#1">启 用</a>
{/if}
{if auth("service/index/sync")}
<a class="layui-btn layui-btn-sm" data-load='{:url("service/index/sync")}?appid={$vo.authorizer_appid}'>同 步</a>
{/if}
{if auth("service/index/remove")}
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除该公众号吗?" data-action="{:url('remove')}" data-csrf="{:systoken('service/index/remove')}" data-value="id#{$vo.id}">删 除</a>
{/if}
{if auth("service/index/clearquota")}
<a class="layui-btn layui-btn-sm layui-btn-primary" data-confirm="每个公众号每个月有10次清零机会,请谨慎使用!" data-load='{:url("service/index/clearquota")}?appid={$vo.authorizer_appid}'>清 零</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
</div>
{/block}

77
application/service/view/index/index_search.html

@ -0,0 +1,77 @@
<fieldset>
<legend>条件搜索</legend>
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" 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="authorizer_appid" value="{$Think.get.authorizer_appid|default=''}" placeholder="请输入微信APPID" 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="nick_name" value="{$Think.get.nick_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 name="service_type" class="layui-select">
<option value="">- 全部 -</option>
{foreach ['0'=>'显示订阅号类型','2'=>'显示服务号类型','3'=>'显示小程序类型'] as $k=>$v}
<!--{if $k.'' eq $Think.get.service_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">
<select class="layui-select" name="status">
{foreach [''=>'- 全部 -','0'=>'已禁用的账号','1'=>'使用中的账号'] as $k=>$v}
{eq name='Think.get.status' value='$k.""'}
<option selected value="{$k}">{$v}</option>
{else}
<option value="{$k}">{$v}</option>
{/eq}
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item layui-inline">
<label class="layui-form-label">注册公司</label>
<div class="layui-input-inline">
<input name="principal_name" value="{$Think.get.principal_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">
<input id="create_at" name="create_at" value="{$Think.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>
<script>
window.form.render();
window.laydate.render({range: true, elem: '#create_at'});
</script>

1
application/service/view/not-auth.html

@ -0,0 +1 @@
还没有授权,请授权公众号

191
application/store/command/AutoRun.php

@ -0,0 +1,191 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\command;
use think\Db;
/**
* 商城数据处理指令
* Class AutoRun
* @package app\store\command
*/
class AutoRun extends \think\console\Command
{
/**
* 配置指令信息
*/
protected function configure()
{
$this->setName('xclean:store')->setDescription('清理过期无效的订单记录');
}
/**
* 业务指令执行
* @param \think\console\Input $input
* @param \think\console\Output $output
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
protected function execute(\think\console\Input $input, \think\console\Output $output)
{
// 自动取消30分钟未支付的订单
$this->autoCancelOrder();
// 清理一天前未支付的订单
$this->autoRemoveOrder();
// 订单自动退款处理
// $this->autoRefundOrder();
// 提现自动打款处理
// $this->autoTransfer();
}
/**
* 自动取消30分钟未支付的订单
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function autoCancelOrder()
{
$datetime = $this->getDatetime('store_order_wait_time');
$where = [['status', 'in', ['1', '2']], ['pay_state', 'eq', '0'], ['create_at', '<', $datetime]];
$count = Db::name('StoreOrder')->where($where)->update([
'status' => '0',
'cancel_state' => '1',
'cancel_at' => date('Y-m-d H:i:s'),
'cancel_desc' => '30分钟未完成支付自动取消订单',
]);
if ($count > 0) {
$this->output->info("共计自动取消了30分钟未支付的{$count}笔订单!");
} else {
$this->output->comment('没有需要自动取消30分钟未支付的订单记录!');
}
}
/**
* 清理一天前未支付的订单
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
private function autoRemoveOrder()
{
$datetime = $this->getDatetime('store_order_clear_time');
$where = [['status', 'eq', '0'], ['pay_state', 'eq', '0'], ['create_at', '<', $datetime]];
$list = Db::name('StoreOrder')->where($where)->limit(20)->select();
if (count($orderNos = array_unique(array_column($list, 'order_no'))) > 0) {
$this->output->info("自动删除前一天已经取消的订单:" . PHP_EOL . join(',' . PHP_EOL, $orderNos));
Db::name('StoreOrder')->whereIn('order_no', $orderNos)->delete();
Db::name('StoreOrderList')->whereIn('order_no', $orderNos)->delete();
} else {
$this->output->comment('没有需要自动删除前一天已经取消的订单!');
}
}
/**
* 订单自动退款操作
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
private function autoRefundOrder()
{
// 未完成退款的订单,执行微信退款操作
foreach (Db::name('StoreOrder')->where(['refund_state' => '1'])->select() as $order) {
try {
$this->output->writeln("正在为 {$order['order_no']} 执行退款操作...");
$result = \We::WePayRefund(config('wechat.wxpay'))->create([
'transaction_id' => $order['pay_no'],
'out_refund_no' => $order['refund_no'],
'total_fee' => $order['price_total'] * 100,
'refund_fee' => $order['pay_price'] * 100,
'refund_account' => 'REFUND_SOURCE_UNSETTLED_FUNDS',
]);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
Db::name('StoreOrder')->where(['order_no' => $order['order_no']])->update([
'refund_state' => '2', 'refund_desc' => '自动退款成功!',
]);
} else {
Db::name('StoreOrder')->where(['order_no' => $order['order_no']])->update([
'refund_desc' => isset($result['err_code_des']) ? $result['err_code_des'] : '自动退款失败',
]);
}
} catch (\Exception $e) {
$this->output->writeln("订单 {$order['order_no']} 执行退款失败,{$e->getMessage()}!");
Db::name('StoreOrder')->where(['order_no' => $order['order_no']])->update(['refund_desc' => $e->getMessage()]);
}
}
$this->output->writeln('自动检测退款订单执行完成!');
}
/**
* 自动企业打款操作
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
private function autoTransfer()
{
# 批量企业打款
foreach (Db::name('StoreProfitUsed')->where(['status' => '1'])->select() as $vo) {
try {
$wechat = \We::WePayTransfers(config('wechat.wxpay'));
$result = $wechat->create([
'partner_trade_no' => $vo['trs_no'],
'openid' => $vo['openid'],
'check_name' => 'NO_CHECK',
'amount' => $vo['pay_price'] * 100,
'desc' => '营销活动拥金提现',
'spbill_create_ip' => '127.0.0.1',
]);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
Db::name('StoreProfitUsed')->where(['trs_no' => $vo['trs_no']])->update([
'status' => '2', 'pay_desc' => '拥金提现成功!', 'pay_no' => $result['payment_no'], 'pay_at' => date('Y-m-d H:i:s'),
]);
} else {
Db::name('StoreProfitUsed')->where(['trs_no' => $vo['trs_no']])->update([
'pay_desc' => isset($result['err_code_des']) ? $result['err_code_des'] : '自动打款失败', 'last_at' => date('Y-m-d H:i:s'),
]);
}
} catch (\Exception $e) {
$this->output->writeln("订单 {$vo['trs_no']} 执行提现失败,{$e->getMessage()}!");
Db::name('StoreProfitUsed')->where(['trs_no' => $vo['trs_no']])->update(['pay_desc' => $e->getMessage()]);
}
}
}
/**
* 获取配置时间
* @param string $code
* @return string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
private function getDatetime($code)
{
$minutes = intval(sysconf($code) * 60);
return date('Y-m-d H:i:s', strtotime("-{$minutes} minutes"));
}
}

61
application/store/controller/Config.php

@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use app\store\service\Extend;
use app\store\service\ExtendService;
use library\Controller;
/**
* 商城参数配置
* Class Config
* @package app\store\controller
*/
class Config extends Controller
{
/**
* 商城参数配置
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '商城参数配置';
$this->applyCsrfToken('save');
$this->query = ExtendService::querySmsBalance();
$this->query2 = ExtendService::querySmsBalance2();
$this->fetch();
}
/**
* 保存商城参数
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function save()
{
if ($this->request->isPost()) {
$this->applyCsrfToken('save');
foreach ($this->request->post() as $k => $v) sysconf($k, $v);
$this->success('商城短信配置保存成功!');
}
}
}

112
application/store/controller/ExpressCompany.php

@ -0,0 +1,112 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
use think\Db;
/**
* 快递公司管理
* Class Express
* @package app\store\controller
*/
class ExpressCompany extends Controller
{
/**
* 指定数据表
* @var string
*/
protected $table = 'StoreExpressCompany';
/**
* 快递公司管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '快递公司管理';
$query = $this->_query($this->table)->equal('status')->like('express_title,express_code');
$query->dateBetween('create_at')->order('status desc,sort desc,id desc')->page();
}
/**
* 添加快递公司
* @auth true
*/
public function add()
{
$this->_form($this->table, 'form');
}
/**
* 编辑快递公司
* @auth true
*/
public function edit()
{
$this->_form($this->table, 'form');
}
/**
* 表单数据处理
* @param array $data
* @auth true
*/
protected function _form_filter(array $data)
{
if ($this->request->isPost()) {
$where = [['express_code', 'eq', $data['express_code']], ['is_deleted', 'eq', '0']];
if (!empty($data['id'])) $where[] = ['id ', 'neq', $data['id']];
if (Db::name($this->table)->where($where)->count() > 0) {
$this->error('该快递编码已经存在,请使用其它编码!');
}
}
}
/**
* 禁用快递公司
* @auth true
*/
public function forbid()
{
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用快递公司
* @auth true
*/
public function resume()
{
$this->_save($this->table, ['status' => '1']);
}
/**
* 删除快递公司
* @auth true
*/
public function remove()
{
$this->_delete($this->table);
}
}

85
application/store/controller/ExpressTemplate.php

@ -0,0 +1,85 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
use think\Db;
/**
* 邮费模板管理
* Class ExpressTemplate
* @package app\store\controller
*/
class ExpressTemplate extends Controller
{
/**
* 指定数据表
* @var string
*/
protected $table = 'StoreExpressTemplate';
/**
* 邮费模板管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index()
{
$this->title = '邮费模板管理';
$filename = env('root_path') . 'public/static/plugs/jquery/area/area.json';
$this->provinces = array_column(json_decode(file_get_contents($filename), true), 'name');
$this->list = Db::name($this->table)->where(['is_default' => '0'])->select();
foreach ($this->list as &$item) $item['rule'] = explode(',', $item['rule']);
$this->default = Db::name($this->table)->where(['is_default' => '1'])->find();
$this->fetch();
}
/**
* 保存邮费模板
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function save()
{
list($list, $idxs, $post) = [[], [], $this->request->post()];
foreach (array_keys($post) as $key) if (stripos($key, 'order_reduction_state_') !== false) {
$idxs[] = str_replace('order_reduction_state_', '', $key);
}
foreach (array_unique($idxs) as $index) if (!empty($post["rule_{$index}"])) $list[] = [
'rule' => join(',', $post["rule_{$index}"]),
// 订单满减配置
'order_reduction_state' => $post["order_reduction_state_{$index}"],
'order_reduction_price' => $post["order_reduction_price_{$index}"],
// 首件邮费配置
'first_number' => $post["first_number_{$index}"],
'first_price' => $post["first_price_{$index}"],
// 首件邮费配置
'next_number' => $post["next_number_{$index}"],
'next_price' => $post["next_price_{$index}"],
// 默认邮费规则
'is_default' => $post["is_default_{$index}"],
];
if (empty($list)) $this->error('请配置有效的邮费规则');
Db::name($this->table)->where('1=1')->delete();
Db::name($this->table)->insertAll($list);
$this->success('邮费规则配置成功!');
}
}

197
application/store/controller/Goods.php

@ -0,0 +1,197 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
use library\tools\Data;
use think\Db;
/**
* 商品信息管理
* Class Goods
* @package app\store\controller
*/
class Goods extends Controller
{
/**
* 指定数据表
* @var string
*/
protected $table = 'StoreGoods';
/**
* 商品信息管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '商品信息管理';
$query = $this->_query($this->table)->equal('status,cate_id')->like('title');
$query->where(['is_deleted' => '0'])->order('sort desc,id desc')->page();
}
/**
* 数据列表处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
protected function _index_page_filter(&$data)
{
$this->clist = Db::name('StoreGoodsCate')->where(['is_deleted' => '0', 'status' => '1'])->select();
$list = Db::name('StoreGoodsList')->where('status', '1')->whereIn('goods_id', array_unique(array_column($data, 'id')))->select();
foreach ($data as &$vo) {
list($vo['list'], $vo['cate']) = [[], []];
foreach ($list as $goods) if ($goods['goods_id'] === $vo['id']) array_push($vo['list'], $goods);
foreach ($this->clist as $cate) if ($cate['id'] === $vo['cate_id']) $vo['cate'] = $cate;
}
}
/**
* 商品库存入库
* @auth true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function stock()
{
if ($this->request->isGet()) {
$GoodsId = $this->request->get('id');
$goods = Db::name('StoreGoods')->where(['id' => $GoodsId])->find();
empty($goods) && $this->error('无效的商品信息,请稍候再试!');
$goods['list'] = Db::name('StoreGoodsList')->where(['goods_id' => $GoodsId])->select();
$this->fetch('', ['vo' => $goods]);
} else {
list($post, $data) = [$this->request->post(), []];
if (isset($post['id']) && isset($post['goods_id']) && is_array($post['goods_id'])) {
foreach (array_keys($post['goods_id']) as $key) if ($post['goods_number'][$key] > 0) array_push($data, [
'goods_id' => $post['goods_id'][$key],
'goods_spec' => $post['goods_spec'][$key],
'number_stock' => $post['goods_number'][$key],
]);
if (!empty($data)) {
Db::name('StoreGoodsStock')->insertAll($data);
\app\store\service\GoodsService::syncStock($post['id']);
$this->success('商品信息入库成功!');
}
}
$this->error('没有需要商品入库的数据!');
}
}
/**
* 添加商品信息
* @auth true
*/
public function add()
{
$this->title = '添加商品信息';
$this->isAddMode = '1';
$this->_form($this->table, 'form');
}
/**
* 编辑商品信息
* @auth true
*/
public function edit()
{
$this->title = '编辑商品信息';
$this->isAddMode = '0';
$this->_form($this->table, 'form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
protected function _form_filter(&$data)
{
// 生成商品ID
if (empty($data['id'])) $data['id'] = Data::uniqidNumberCode(10);
if ($this->request->isGet()) {
$fields = 'goods_spec,goods_id,status,price_market market,price_selling selling,number_virtual `virtual`,number_express express';
$defaultValues = Db::name('StoreGoodsList')->where(['goods_id' => $data['id']])->column($fields);
$this->defaultValues = json_encode($defaultValues, JSON_UNESCAPED_UNICODE);
$this->cates = Db::name('StoreGoodsCate')->where(['is_deleted' => '0', 'status' => '1'])->order('sort desc,id desc')->select();
} elseif ($this->request->isPost()) {
Db::name('StoreGoodsList')->where(['goods_id' => $data['id']])->update(['status' => '0']);
foreach (json_decode($data['lists'], true) as $vo) Data::save('StoreGoodsList', [
'goods_id' => $data['id'],
'goods_spec' => $vo[0]['key'],
'price_market' => $vo[0]['market'],
'price_selling' => $vo[0]['selling'],
'number_virtual' => $vo[0]['virtual'],
'number_express' => $vo[0]['express'],
'status' => $vo[0]['status'] ? 1 : 0,
], 'goods_spec', ['goods_id' => $data['id']]);
}
}
/**
* 表单结果处理
* @param boolean $result
*/
protected function _form_result($result)
{
if ($result && $this->request->isPost()) {
$this->success('商品编辑成功!', 'javascript:history.back()');
}
}
/**
* 禁用商品信息
* @auth true
*/
public function forbid()
{
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用商品信息
* @auth true
*/
public function resume()
{
$this->_save($this->table, ['status' => '1']);
}
/**
* 删除商品信息
* @auth true
*/
public function remove()
{
$this->_delete($this->table);
}
}

97
application/store/controller/GoodsCate.php

@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
/**
* 商品分类管理
* Class GoodsCate
* @package app\store\controller
*/
class GoodsCate extends Controller
{
/**
* 绑定数据表
* @var string
*/
protected $table = 'StoreGoodsCate';
/**
* 商品分类管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '商品分类管理';
$query = $this->_query($this->table)->like('title')->equal('status');
$query->where(['is_deleted' => '0'])->order('sort desc,id desc')->page();
}
/**
* 添加商品分类
* @auth true
*/
public function add()
{
$this->title = '添加商品分类';
$this->_form($this->table, 'form');
}
/**
* 编辑商品分类
* @auth true
*/
public function edit()
{
$this->title = '编辑商品分类';
$this->_form($this->table, 'form');
}
/**
* 禁用商品分类
* @auth true
*/
public function forbid()
{
$this->_save($this->table, ['status' => '0']);
}
/**
* 启用商品分类
* @auth true
*/
public function resume()
{
$this->_save($this->table, ['status' => '1']);
}
/**
* 删除商品分类
* @auth true
*/
public function remove()
{
$this->_delete($this->table);
}
}

50
application/store/controller/Member.php

@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
/**
* 会员信息管理
* Class Member
* @package app\store\controller
*/
class Member extends Controller
{
/**
* 绑定数据表
* @var string
*/
protected $table = 'StoreMember';
/**
* 会员信息管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '会员信息管理';
$query = $this->_query($this->table)->like('nickname,phone')->equal('vip_level');
$query->dateBetween('create_at')->order('id desc')->page();
}
}

61
application/store/controller/Message.php

@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://demo.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
// | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
// +----------------------------------------------------------------------
namespace app\store\controller;
use library\Controller;
/**
* 短信发送管理
* Class Message
* @package app\store\controller
*/
class Message extends Controller
{
/**
* 绑定数据表
* @var string
*/
protected $table = 'StoreMemberSmsHistory';
/**
* 短信发送管理
* @auth true
* @menu true
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public function index()
{
$this->title = '短信发送管理';
$query = $this->_query($this->table)->like('phone,content,result');
$query->dateBetween('create_at')->order('id desc')->page();
}
/**
* 删除短信记录
* @auth true
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function remove()
{
$this->_delete($this->table);
}
}

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

Loading…
Cancel
Save