wupengfei 2 years ago
parent
commit
c245401ec5
100 changed files with 18520 additions and 0 deletions
  1. 11 0
      .gitignore
  2. 21 0
      LICENSE
  3. 859 0
      admin_v5.sql
  4. 180 0
      application/admin/controller/Auth.php
  5. 130 0
      application/admin/controller/Config.php
  6. 204 0
      application/admin/controller/Index.php
  7. 118 0
      application/admin/controller/Login.php
  8. 160 0
      application/admin/controller/Menu.php
  9. 62 0
      application/admin/controller/Official.php
  10. 94 0
      application/admin/controller/Oplog.php
  11. 173 0
      application/admin/controller/User.php
  12. 122 0
      application/admin/controller/Versions.php
  13. 130 0
      application/admin/controller/api/Plugs.php
  14. 65 0
      application/admin/controller/api/Update.php
  15. 159 0
      application/admin/sys.php
  16. 3659 0
      application/admin/view/api/plugs/icon.html
  17. 116 0
      application/admin/view/auth/apply.html
  18. 30 0
      application/admin/view/auth/form.html
  19. 80 0
      application/admin/view/auth/index.html
  20. 42 0
      application/admin/view/auth/index_search.html
  21. 80 0
      application/admin/view/config/info.html
  22. 20 0
      application/admin/view/config/storage-local.html
  23. 80 0
      application/admin/view/config/storage-oss.html
  24. 80 0
      application/admin/view/config/storage-qiniu.html
  25. 57 0
      application/admin/view/config/system-config.html
  26. 134 0
      application/admin/view/index/index.html
  27. 228 0
      application/admin/view/index/main.html
  28. 57 0
      application/admin/view/login/index.html
  29. 11 0
      application/admin/view/main.html
  30. 89 0
      application/admin/view/menu/form.html
  31. 80 0
      application/admin/view/menu/index.html
  32. 18 0
      application/admin/view/official/index-about-us.html
  33. 18 0
      application/admin/view/official/index-agent-notice.html
  34. 18 0
      application/admin/view/official/index-agreement.html
  35. 18 0
      application/admin/view/official/index-customer-service.html
  36. 18 0
      application/admin/view/official/index-integral-channel.html
  37. 18 0
      application/admin/view/official/index-partner-item.html
  38. 18 0
      application/admin/view/official/index-privacy.html
  39. 18 0
      application/admin/view/official/index-refund-desc.html
  40. 18 0
      application/admin/view/official/index-sign-rule.html
  41. 18 0
      application/admin/view/official/index-user-equity.html
  42. 18 0
      application/admin/view/official/index-write-off.html
  43. 48 0
      application/admin/view/official/index.html
  44. 32 0
      application/admin/view/official/platform-set.html
  45. 68 0
      application/admin/view/oplog/index.html
  46. 56 0
      application/admin/view/oplog/index_search.html
  47. 73 0
      application/admin/view/user/form.html
  48. 77 0
      application/admin/view/user/index.html
  49. 57 0
      application/admin/view/user/index_search.html
  50. 57 0
      application/admin/view/user/pass.html
  51. 33 0
      application/admin/view/versions/form.html
  52. 45 0
      application/admin/view/versions/index.html
  53. 41 0
      application/api/common.php
  54. 380 0
      application/api/controller/Alipay.php
  55. 865 0
      application/api/controller/ApiRedis.php
  56. 100 0
      application/api/controller/Appointment.php
  57. 120 0
      application/api/controller/Area.php
  58. 215 0
      application/api/controller/Base.php
  59. 536 0
      application/api/controller/ChinaSpell.php
  60. 284 0
      application/api/controller/Collect.php
  61. 388 0
      application/api/controller/CustomOrder.php
  62. 344 0
      application/api/controller/ExchangeOrder.php
  63. 607 0
      application/api/controller/Expedite.php
  64. 199 0
      application/api/controller/General.php
  65. 357 0
      application/api/controller/Information.php
  66. 443 0
      application/api/controller/Login.php
  67. 518 0
      application/api/controller/MallActivity.php
  68. 387 0
      application/api/controller/MallIndex.php
  69. 159 0
      application/api/controller/Message.php
  70. 109 0
      application/api/controller/Nutrition.php
  71. 1325 0
      application/api/controller/Order.php
  72. 50 0
      application/api/controller/Qc.php
  73. 235 0
      application/api/controller/Sign.php
  74. 83 0
      application/api/controller/Task.php
  75. 303 0
      application/api/controller/Trolley.php
  76. 151 0
      application/api/controller/Upload.php
  77. 488 0
      application/api/controller/UserCenter.php
  78. 135 0
      application/api/controller/UserCoupon.php
  79. 337 0
      application/api/controller/UserManage.php
  80. 178 0
      application/api/controller/UserRank.php
  81. 202 0
      application/api/controller/Video.php
  82. 279 0
      application/api/controller/WalletManage.php
  83. 166 0
      application/api/controller/WeChatPay.php
  84. 26 0
      application/api/controller/WeChatPort.php
  85. 275 0
      application/common.php
  86. 8 0
      application/common/model/BaseGoods.php
  87. 10 0
      application/common/model/BaseGoodsItem.php
  88. 16 0
      application/common/model/ChinaArea.php
  89. 9 0
      application/common/model/CouponConfig.php
  90. 8 0
      application/common/model/DeliveryAddress.php
  91. 9 0
      application/common/model/Depot.php
  92. 28 0
      application/common/model/DepotGoods.php
  93. 8 0
      application/common/model/DepotGoodsItem.php
  94. 8 0
      application/common/model/DiscountActivity.php
  95. 8 0
      application/common/model/DiscountGoods.php
  96. 8 0
      application/common/model/ExchangeGoods.php
  97. 8 0
      application/common/model/ExchangeOrder.php
  98. 8 0
      application/common/model/GiftCate.php
  99. 12 0
      application/common/model/GiftGoods.php
  100. 12 0
      application/common/model/GiftOrder.php

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+/.git
+/.svn
+/.idea
+/runtime
+/safefile
+/nbproject
+/config/cert
+/composer.lock
+/public/upload
+public/static/theme/css/console.*.css
+public/static/theme/css/console.*.css.map

+ 21 - 0
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.

+ 859 - 0
admin_v5.sql

@@ -0,0 +1,859 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : local.server.cuci.cc
+ Source Server Type    : MySQL
+ Source Server Version : 50562
+ Source Host           : server.cuci.cc:3306
+ Source Schema         : admin_v5
+
+ Target Server Type    : MySQL
+ Target Server Version : 50562
+ File Encoding         : 65001
+
+ Date: 19/08/2019 10:34:31
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for company_user
+-- ----------------------------
+DROP TABLE IF EXISTS `company_user`;
+CREATE TABLE `company_user`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '员工姓名',
+  `svn_username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '员工账号',
+  `svn_password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '员工密码',
+  `svn_authorize` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '权限授权',
+  `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '员工身份',
+  `entry_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '入职日期',
+  `leave_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '离职日期',
+  `become_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '转正日期',
+  `contact_qq` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系QQ',
+  `contact_mail` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系邮箱',
+  `contact_phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '联系手机',
+  `mobile_macs` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '打卡手机',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0禁用,1正常,2离职)',
+  `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,
+  UNIQUE INDEX `idx_company_user_nickname`(`nickname`) USING BTREE,
+  INDEX `idx_company_user_svn_username`(`svn_username`) USING BTREE,
+  INDEX `idx_company_user_deleted`(`is_deleted`) USING BTREE,
+  INDEX `idx_company_user_status`(`status`) USING BTREE,
+  INDEX `idx_company_user_type`(`user_type`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '企业-员工信息';
+
+-- ----------------------------
+-- Table structure for company_user_auth
+-- ----------------------------
+DROP TABLE IF EXISTS `company_user_auth`;
+CREATE TABLE `company_user_auth`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '权限名称',
+  `path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '权限路径',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '状态(0禁用,1正常)',
+  `desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '权限描述',
+  `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,
+  INDEX `idx_company_user_auth_status`(`status`) USING BTREE,
+  INDEX `idx_company_user_auth_deleted`(`is_deleted`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '企业-仓库权限';
+
+-- ----------------------------
+-- Table structure for company_user_clock
+-- ----------------------------
+DROP TABLE IF EXISTS `company_user_clock`;
+CREATE TABLE `company_user_clock`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `uid` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '用户ID',
+  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户姓名',
+  `ip` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限名称',
+  `mac` char(17) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '状态(1:禁用,2:启用)',
+  `desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注说明',
+  `date` date NULL DEFAULT NULL,
+  `start_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `end_at` datetime NULL DEFAULT NULL COMMENT '结束时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_company_user_clock_date`(`date`) USING BTREE,
+  INDEX `idx_company_user_clock_uid`(`uid`) USING BTREE,
+  INDEX `idx_company_user_clock_name`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '企业-打卡记录';
+
+-- ----------------------------
+-- 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 `idx_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 `idx_store_goods_status`(`status`) USING BTREE,
+  INDEX `idx_store_goods_cate_id`(`cate_id`) USING BTREE,
+  INDEX `idx_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 `idx_store_goods_cate_is_deleted`(`is_deleted`) USING BTREE,
+  INDEX `idx_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 `idx_store_goods_list_id`(`goods_id`) USING BTREE,
+  INDEX `idx_store_goods_list_spec`(`goods_spec`) USING BTREE,
+  INDEX `idx_store_goods_list_status`(`status`) USING BTREE,
+  INDEX `idx_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 `idx_store_goods_stock_gid`(`goods_id`) USING BTREE,
+  INDEX `idx_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 `idx_store_member_openid`(`openid`) USING BTREE,
+  INDEX `idx_store_member_phone`(`phone`) USING BTREE,
+  INDEX `idx_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 `idx_store_member_address_mid`(`mid`) USING BTREE,
+  INDEX `idx_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 DEFAULT '0' COMMENT '会员ID',
+  `phone` varchar(20) DEFAULT '' COMMENT '目标手机',
+  `content` varchar(512) DEFAULT '' COMMENT '短信内容',
+  `region` varchar(100) DEFAULT '' COMMENT '区域编码',
+  `result` varchar(100) DEFAULT '' COMMENT '返回结果',
+  `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_store_member_sms_history_phone` (`phone`) USING BTREE,
+  KEY `idx_store_member_sms_history_mid` (`mid`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 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 `idx_store_groups_order_mid`(`mid`) USING BTREE,
+  INDEX `idx_store_groups_order_order_no`(`order_no`) USING BTREE,
+  INDEX `idx_store_groups_order_pay_state`(`pay_state`) USING BTREE,
+  INDEX `idx_store_groups_order_cancel_state`(`cancel_state`) USING BTREE,
+  INDEX `idx_store_groups_order_refund_state`(`refund_state`) USING BTREE,
+  INDEX `idx_store_groups_order_status`(`status`) USING BTREE,
+  INDEX `idx_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 `idx_store_goods_list_id`(`goods_id`) USING BTREE,
+  INDEX `idx_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 `idx_system_auth_status`(`status`) USING BTREE,
+  INDEX `idx_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 `idx_system_auth_auth`(`auth`) USING BTREE,
+  INDEX `idx_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 `idx_system_config_name`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 81 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', 'dev');
+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', '5caf4b0727f6e46a7e6ccbe773cc955d');
+INSERT INTO `system_config` VALUES (60, 'wechat_thr_appurl', '消息推送地址:http://127.0.0.1:2314/wechat/api.push');
+INSERT INTO `system_config` VALUES (61, 'component_appid', 'wx28b58798480874f9');
+INSERT INTO `system_config` VALUES (62, 'component_appsecret', '8d0e1ec14ea0adc5027dd0ad82c64bc9');
+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');
+INSERT INTO `system_config` VALUES (74, 'sms_zt_username2', '可以找CUCI申请2');
+INSERT INTO `system_config` VALUES (75, 'sms_zt_password2', '可以找CUCI申请2');
+INSERT INTO `system_config` VALUES (76, 'sms_secure2', '可以找CUCI申请2');
+INSERT INTO `system_config` VALUES (77, 'sms_reg_template2', '您的验证码为{code},请在十分钟内完成操作!2');
+INSERT INTO `system_config` VALUES (78, 'michat_appid', '2882303761518074614');
+INSERT INTO `system_config` VALUES (79, 'michat_appkey', '5861807470614');
+INSERT INTO `system_config` VALUES (80, 'michat_appsecert', 'CP/WUTUgDuyOxgLQ5ztesg==');
+
+-- ----------------------------
+-- 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 `idx_system_data_name`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-数据';
+
+-- ----------------------------
+-- Records of system_data
+-- ----------------------------
+INSERT INTO `system_data` VALUES (1, 'menudata', '[{\"name\":\"请输入名称\",\"type\":\"scancode_push\",\"key\":\"scancode_push\"}]');
+
+-- ----------------------------
+-- 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 `idx_system_menu_node`(`node`(191)) USING BTREE,
+  INDEX `idx_system_menu_status`(`status`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 62 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');
+INSERT INTO `system_menu` VALUES (56, 40, '微信粉丝管理', '', 'layui-icon layui-icon-username', 'service/fans/index', '', '_self', 0, 1, '2019-07-23 09:57:24');
+INSERT INTO `system_menu` VALUES (57, 0, '企业管理', '', '', '#', '', '_self', 150, 1, '2019-08-08 17:20:29');
+INSERT INTO `system_menu` VALUES (58, 57, '基础管理', '', '', '#', '', '_self', 0, 1, '2019-08-08 17:20:42');
+INSERT INTO `system_menu` VALUES (59, 58, '企业员工管理', '', 'layui-icon layui-icon-username', 'company/user/index', '', '_self', 0, 1, '2019-08-08 17:20:59');
+INSERT INTO `system_menu` VALUES (60, 58, '仓库权限管理', '', 'layui-icon layui-icon-template-1', 'company/auth/index', '', '_self', 0, 1, '2019-08-08 18:39:37');
+INSERT INTO `system_menu` VALUES (61, 58, '网络打卡管理', '', 'layui-icon layui-icon-engine', 'company/clock/index', '', '_self', 0, 1, '2019-08-09 14:44:23');
+
+-- ----------------------------
+-- Table structure for system_queue
+-- ----------------------------
+DROP TABLE IF EXISTS `system_queue`;
+CREATE TABLE `system_queue`  (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '任务名称',
+  `data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '执行参数',
+  `status` tinyint(1) UNSIGNED NULL DEFAULT 1 COMMENT '任务状态(1新任务,2处理中,3成功,4失败)',
+  `preload` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '执行内容',
+  `time` bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT '执行时间',
+  `double` tinyint(1) NULL DEFAULT 1 COMMENT '单例模式',
+  `desc` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '状态描述',
+  `start_at` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '开始时间',
+  `end_at` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '结束时间',
+  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_system_queue_double`(`double`) USING BTREE,
+  INDEX `idx_system_queue_time`(`time`) USING BTREE,
+  INDEX `idx_system_queue_title`(`title`) USING BTREE,
+  INDEX `idx_system_queue_create_at`(`create_at`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统-任务';
+
+-- ----------------------------
+-- 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 '权限授权',
+  `tags` 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,
+  INDEX `idx_system_user_username`(`username`) USING BTREE,
+  INDEX `idx_system_user_status`(`status`) USING BTREE,
+  INDEX `idx_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-08-18 18:34:14', '127.0.0.1', 661, '', '', '', 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 `idx_wechat_fans_openid`(`openid`) USING BTREE,
+  INDEX `idx_wechat_fans_unionid`(`unionid`) USING BTREE,
+  INDEX `idx_wechat_fans_is_back`(`is_black`) USING BTREE,
+  INDEX `idx_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 `idx_wechat_fans_tags_id`(`id`) USING BTREE,
+  INDEX `idx_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 `idx_wechat_keys_appid`(`appid`) USING BTREE,
+  INDEX `idx_wechat_keys_type`(`type`) USING BTREE,
+  INDEX `idx_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 `idx_wechat_media_appid`(`appid`) USING BTREE,
+  INDEX `idx_wechat_media_md5`(`md5`) USING BTREE,
+  INDEX `idx_wechat_media_type`(`type`) USING BTREE,
+  INDEX `idx_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 `idx_wechat_news_artcle_id`(`article_id`) USING BTREE,
+  INDEX `idx_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 `idx_wechat_service_config_authorizer_appid`(`authorizer_appid`) USING BTREE,
+  INDEX `idx_wechat_service_config_status`(`status`) USING BTREE,
+  INDEX `idx_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 - 0
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 library\Controller;
+use library\service\AdminService;
+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()
+    {
+        $map = ['auth' => input('id', '0')];
+        $action = strtolower(input('action', ''));
+        if ($action === 'get') {
+            $checkeds = Db::name('SystemAuthNode')->where($map)->column('node');
+            $this->success('获取权限节点成功!', AdminService::instance()->getTree($checkeds));
+        } elseif ($action === 'save') {
+            list($post, $data) = [$this->request->post(), []];
+            foreach (isset($post['nodes']) ? $post['nodes'] : [] as $node) {
+                $data[] = ['auth' => $map['auth'], 'node' => $node];
+            }
+            Db::name('SystemAuthNode')->where($map)->delete();
+            Db::name('SystemAuthNode')->insertAll($data);
+            AdminService::instance()->apply(true);
+            $this->success('权限授权更新成功!', 'javascript:history.back()');
+        } else {
+            $this->title = '权限配置节点';
+            $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 {
+            AdminService::instance()->apply(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("权限删除失败,请稍候再试!");
+        }
+    }
+
+}

+ 130 - 0
application/admin/controller/Config.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\controller;
+
+use library\Controller;
+use think\exception\HttpResponseException;
+use think\facade\Request;
+
+/**
+ * 系统参数配置
+ * 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->fetch();
+    }
+
+    /**
+     * 修改系统能数配置
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function config()
+    {
+        $this->applyCsrfToken();
+        if (Request::isGet()) {
+            $this->fetch('system-config');
+        }
+        foreach (Request::post() as $key => $value) {
+            sysconf($key, $value);
+        }
+        $this->success('系统参数配置成功!');
+    }
+
+    /**
+     * 文件存储引擎
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function file()
+    {
+        $this->applyCsrfToken();
+        if (Request::isGet()) {
+            $this->type = input('type', 'local');
+            $this->fetch("storage-{$this->type}");
+        }
+        $post = 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('文件存储配置成功!');
+        }
+    }
+
+}

+ 204 - 0
application/admin/controller/Index.php

@@ -0,0 +1,204 @@
+<?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 library\service\AdminService;
+use library\service\MenuService;
+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 = '系统管理后台';
+        $auth = AdminService::instance()->apply(true);
+        $this->menus = MenuService::instance()->getTree();
+        if (empty($this->menus) && !$auth->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'];
+        $beginYesterday=mktime(0,0,0,date('m'),date('d')-1,date('Y'));
+        $endYesterday=mktime(0,0,0,date('m'),date('d'),date('Y'))-1;
+        $beginToday=mktime(0,0,0,date('m'),date('d'),date('Y'));
+        $endToday=mktime(0,0,0,date('m'),date('d')+1,date('Y'))-1;
+
+        $user_num = \app\common\model\User::where('status',1)->where('is_deleted',0)->count();
+        $agency_num =  \app\common\model\User::where('is_agency',1)->where('is_deleted',0)->count();
+        $partner_num =  \app\common\model\User::where('is_partner',1)->where('is_deleted',0)->count();
+        $goods_num =  \app\common\model\StoreGoods::where('is_deleted',0)->count();
+        $order_num =  \app\common\model\GoodsOrder::where('status','>=',1)->count();
+        $order_money =  \app\common\model\GoodsOrder::where('status','>=',1)->sum('price_total');
+        $gift_order_num =  \app\common\model\GiftOrder::count();
+        $gift_order_money =  \app\common\model\GiftOrder::where('status',1)->sum('price_total');
+        $news_num =  \app\common\model\InformationArticle::where('is_deleted',0)->count();
+        $video_num =  \app\common\model\VideoIntro::where('is_deleted',0)->count();
+
+        $new_user =  \app\common\model\User::where('status',1)->whereBetweenTime('create_at',$beginToday,$endToday)->count();
+
+
+        $data = [
+            'user_num' => $user_num,
+            'agency_num' => $agency_num,
+            'partner_num' => $partner_num,
+            'goods_num' => $goods_num,
+            'order_num' => $order_num,
+            'order_money' => $order_money,
+            'news_num' => $news_num,
+            'video_num' => $video_num,
+            'new_user' => $new_user,
+            'gift_order_num' => $gift_order_num,
+            'gift_order_money' => $gift_order_money,
+        ];
+        $this->assign('data',$data);
+        $this->fetch();
+    }
+
+    /**
+     * 修改密码
+     * @login true
+     * @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('user.id'))) {
+            $this->error('只能修改当前用户的密码!');
+        }
+        if (!AdminService::instance()->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('旧密码验证失败,请重新输入!');
+            }
+            if (Data::save('SystemUser', ['id' => $user['id'], 'password' => md5($data['password'])])) {
+                $this->success('密码修改成功,下次请使用新密码登录!', '');
+            } else {
+                $this->error('密码修改失败,请稍候再试!');
+            }
+        }
+    }
+
+    /**
+     * 修改用户资料
+     * @login true
+     * @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 (!AdminService::instance()->isLogin()) {
+            $this->error('需要登录才能操作哦!');
+        }
+        $this->applyCsrfToken();
+        if (intval($id) === intval(session('user.id'))) {
+            $this->_form('SystemUser', 'admin@user/form', 'id', [], ['id' => $id]);
+        } else {
+            $this->error('只能修改登录用户的资料!');
+        }
+    }
+
+    /**
+     * 清理运行缓存
+     * @auth true
+     */
+    public function clearRuntime()
+    {
+        try {
+            Console::call('clear');
+            Console::call('xclean:session');
+            $this->success('清理运行缓存成功!');
+        } catch (HttpResponseException $exception) {
+            throw $exception;
+        } catch (\Exception $e) {
+            $this->error("清理运行缓存失败,{$e->getMessage()}");
+        }
+    }
+
+    /**
+     * 压缩发布系统
+     */
+    public function buildOptimize()
+    {
+        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()}");
+        }
+    }
+
+}

+ 118 - 0
application/admin/controller/Login.php

@@ -0,0 +1,118 @@
+<?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 library\service\AdminService;
+use library\service\CaptchaService;
+use library\service\SystemService;
+use library\tools\Data;
+use think\Db;
+use think\facade\Request;
+
+/**
+ * 用户登录管理
+ * 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()
+    {
+        if (Request::isGet()) {
+            if (AdminService::instance()->isLogin()) {
+                $this->redirect('@admin');
+            } else {
+                $this->title = '系统登录';
+                $this->captcha_type = 'login_captcha';
+                $this->captcha_token = Data::uniqidDateCode(18);
+                $this->app->session->set($this->captcha_type, $this->captcha_token);
+                $this->devmode = SystemService::instance()->checkRunMode('dev');
+                $this->fetch();
+            }
+        } else {
+            $data = $this->_vali([
+                'username.require' => '登录账号不能为空!',
+                'username.min:4'   => '登录账号长度不能少于4位有效字符!',
+                'password.require' => '登录密码不能为空!',
+                'password.min:4'   => '登录密码长度不能少于4位有效字符!',
+                'verify.require'   => '图形验证码不能为空!',
+                'uniqid.require'   => '图形验证标识不能为空!',
+            ]);
+            if (!CaptchaService::instance()->check($data['verify'], $data['uniqid'])) {
+                $this->error('图形验证码验证失败,请重新输入!');
+            }
+            // 用户信息验证
+            $map = ['is_deleted' => '0', 'username' => $data['username']];
+            $user = Db::name('SystemUser')->where($map)->order('id desc')->find();
+            if (empty($user)) {
+                $this->error('登录账号或密码错误,请重新输入1!');
+            }
+            if (md5("{$user['password']}{$data['uniqid']}") !== $data['password']) {
+                $this->error('登录账号或密码错误,请重新输入2!');
+            }
+            if (empty($user['status'])) {
+                $this->error('账号已经被禁用,请联系管理员!');
+            }
+            Db::name('SystemUser')->where(['id' => $user['id']])->update([
+                'login_ip'  => Request::ip(),
+                'login_at'  => Db::raw('now()'),
+                'login_num' => Db::raw('login_num+1'),
+            ]);
+            $this->app->session->set('user', $user);
+            AdminService::instance()->apply(true);
+            sysoplog('系统管理', '用户登录系统后台成功');
+            $this->success('登录成功', url('@admin'));
+        }
+    }
+
+    /**
+     * 生成验证码
+     * 需要指定类型及令牌
+     */
+    public function captcha()
+    {
+        $image = CaptchaService::instance();
+        $this->type = input('type', 'captcha-type');
+        $this->token = input('token', 'captcha-token');
+        $captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
+        if ($this->app->session->get($this->type) === $this->token) {
+            $captcha['code'] = $image->getCode();
+            $this->app->session->delete($this->type);
+        }
+        $this->success('生成验证码成功', $captcha);
+    }
+
+    /**
+     * 退出登录
+     */
+    public function out()
+    {
+        $this->app->session->clear();
+        $this->app->session->destroy();
+        $this->success('退出登录成功!', url('@admin/login'));
+    }
+
+}

+ 160 - 0
application/admin/controller/Menu.php

@@ -0,0 +1,160 @@
+<?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 library\service\MenuService;
+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'] = trim(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()) {
+            // 读取系统功能节点
+            $this->nodes = MenuService::instance()->getList();
+            // 选择自己的上级菜单
+            if (empty($vo['pid']) && $this->request->get('pid', '0')) $vo['pid'] = $this->request->get('pid', '0');
+            // 列出可选上级菜单
+            $menus = Db::name($this->table)->where(['status' => '1'])->order('sort desc,id asc')->column('id,pid,url,title');
+            $this->menus = Data::arr2table(array_merge($menus, [['id' => '0', 'pid' => '-1', 'url' => '#', 'title' => '顶部菜单']]));
+            if (isset($vo['id'])) foreach ($this->menus as $key => $menu) if ($menu['id'] === $vo['id']) $vo = $menu;
+            foreach ($this->menus as $key => &$menu) {
+                if ($menu['spt'] >= 3 || $menu['url'] !== '#') unset($this->menus[$key]);
+                if (isset($vo['spt']) && $vo['spt'] <= $menu['spt']) unset($this->menus[$key]);
+            }
+        }
+    }
+
+    /**
+     * 启用系统菜单
+     * @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);
+    }
+
+}

+ 62 - 0
application/admin/controller/Official.php

@@ -0,0 +1,62 @@
+<?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\common\service\ExtendService;
+use library\Controller;
+
+/**
+ * 参数配置
+ * Class Official
+ * @package app\admin\controller
+ */
+class Official extends Controller
+{
+
+    /**
+     * 参数配置
+     * @auth true
+     * @menu true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function index()
+    {
+        $this->title = '参数配置';
+        $this->applyCsrfToken('save');
+        $this->query = ExtendService::queryChinaSmsBalance();
+        $this->query2 = ExtendService::queryGlobeSmsBalance();
+        $this->crystal_switch = sysconf('crystal_switch');
+        $this->sign_money_switch = sysconf('sign_money_switch');
+        $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('参数设置保存成功!');
+        }
+    }
+
+}

+ 94 - 0
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);
+    }
+
+}

+ 173 - 0
application/admin/controller/User.php

@@ -0,0 +1,173 @@
+<?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 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('两次输入的密码不一致!');
+            }
+            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()) {
+            // 用户权限处理
+            $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'], 'is_deleted' => '0'])->count() > 0) {
+                $this->error("账号{$data['username']}已经存在,请使用其它账号!");
+            }
+        } 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);
+    }
+
+}

+ 122 - 0
application/admin/controller/Versions.php

@@ -0,0 +1,122 @@
+<?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;
+
+/**
+ * 版本管理
+ * Class Versions
+ * @package app\admin\controller
+ */
+class Versions extends Controller
+{
+    /**
+     * 绑定数据表
+     * @var string
+     */
+    protected $table = 'store_versions';
+
+    /**
+     * 版本管理
+     * @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();
+    }
+    /**
+     * 数据列表处理
+     * @param array $data
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    protected function _index_page_filter(&$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->title = '添加版本';
+        $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->title = '编辑版本';
+        $this->_form($this->table, 'form');
+    }
+
+    /**
+     * 禁用版本
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function forbid()
+    {
+        $this->_save($this->table, ['status' => '0']);
+    }
+
+    /**
+     * 启用版本
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function resume()
+    {
+        $this->_save($this->table, ['status' => '1']);
+    }
+
+    /**
+     * 删除版本
+     * @auth true
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function remove()
+    {
+        $this->_delete($this->table);
+    }
+
+}

+ 130 - 0
application/admin/controller/api/Plugs.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\controller\api;
+
+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();
+    }
+
+    /**
+     * 获取文件上传参数
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function check()
+    {
+        $diff1 = explode(',', strtolower(input('exts', '')));
+        $diff2 = explode(',', strtolower(sysconf('storage_local_exts')));
+        $exts = array_intersect($diff1, $diff2);
+        $this->success('获取文件上传参数', [
+            'exts' => join('|', $exts),
+            'mime' => File::mine($exts),
+            'type' => $this->getUploadType(),
+            'data' => $this->getUploadData(),
+        ]);
+    }
+
+    /**
+     * 后台通用文件上传
+     * @login true
+     * @return \think\response\Json
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function upload()
+    {
+        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 array
+     * @throws \think\Exception
+     */
+    private function getUploadData()
+    {
+        if ($this->getUploadType() === 'qiniu') {
+            $file = File::instance('qiniu');
+            return ['url' => $file->upload(true), 'token' => $file->buildUploadToken(), 'uptype' => $this->getUploadType()];
+        } else {
+            return ['url' => '?s=admin/api.plugs/upload', 'token' => uniqid('local_upload_'), 'uptype' => $this->getUploadType()];
+        }
+    }
+
+    /**
+     * 获取文件上传方式
+     * @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()));
+        }
+    }
+
+}

+ 65 - 0
application/admin/controller/api/Update.php

@@ -0,0 +1,65 @@
+<?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
+{
+    /**
+     * 访问权限
+     */
+    protected function initialize()
+    {
+        $domain = $this->app->request->host(true);
+        $isDemo = is_numeric(stripos($domain, 'thinkadmin.top'));
+        $isLocal = in_array($domain, ['127.0.0.1', 'localhost']);
+        if (!$isLocal && !$isDemo) $this->error('只允许访问本地或官方代码!');
+    }
+
+    /**
+     * 获取文件列表
+     */
+    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('获取文件内容失败!');
+        }
+    }
+
+}

+ 159 - 0
application/admin/sys.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
+// +----------------------------------------------------------------------
+
+use library\File;
+use library\service\AdminService;
+use library\service\CaptchaService;
+use library\service\SystemService;
+use think\Db;
+use think\facade\Middleware;
+use think\facade\Route;
+use think\Request;
+
+if (!function_exists('auth')) {
+    /**
+     * 节点访问权限检查
+     * @param string $node 需要检查的节点
+     * @return boolean
+     * @throws ReflectionException
+     */
+    function auth($node)
+    {
+        return AdminService::instance()->check($node);
+    }
+}
+
+if (!function_exists('sysdata')) {
+    /**
+     * JSON 数据读取与存储
+     * @param string $name 数据名称
+     * @param mixed $value 数据内容
+     * @return mixed
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     */
+    function sysdata($name, $value = null)
+    {
+        if (is_null($value)) {
+            return SystemService::instance()->getData($name);
+        } else {
+            return SystemService::instance()->setData($name, $value);
+        }
+    }
+}
+
+if (!function_exists('sysoplog')) {
+    /**
+     * 写入系统日志
+     * @param string $action 日志行为
+     * @param string $content 日志内容
+     * @return boolean
+     */
+    function sysoplog($action, $content)
+    {
+        return SystemService::instance()->setOplog($action, $content);
+    }
+}
+
+if (!function_exists('sysqueue')) {
+    /**
+     * 创建异步处理任务
+     * @param string $title 任务名称
+     * @param string $loade 执行内容
+     * @param integer $later 延时执行时间
+     * @param array $data 任务附加数据
+     * @param integer $double 任务多开
+     * @return boolean
+     * @throws \think\Exception
+     */
+    function sysqueue($title, $loade, $later = 0, $data = [], $double = 1)
+    {
+        $map = [['title', 'eq', $title], ['status', 'in', [1, 2]]];
+        if (empty($double) && Db::name('SystemQueue')->where($map)->count() > 0) {
+            throw new \think\Exception('该任务已经创建,请耐心等待处理完成!');
+        }
+        $result = Db::name('SystemQueue')->insert([
+            'title'  => $title, 'preload' => $loade,
+            'data'   => json_encode($data, JSON_UNESCAPED_UNICODE),
+            'time'   => $later > 0 ? time() + $later : time(),
+            'double' => intval($double), 'create_at' => date('Y-m-d H:i:s'),
+        ]);
+        return $result !== false;
+    }
+}
+
+if (!function_exists('local_image')) {
+    /**
+     * 下载远程文件到本地
+     * @param string $url 远程图片地址
+     * @param boolean $force 是否强制重新下载
+     * @param integer $expire 强制本地存储时间
+     * @return string
+     */
+    function local_image($url, $force = false, $expire = 0)
+    {
+        $result = File::down($url, $force, $expire);
+        if (isset($result['url'])) {
+            return $result['url'];
+        } else {
+            return $url;
+        }
+    }
+}
+
+if (!function_exists('base64_image')) {
+    /**
+     * base64 图片上传接口
+     * @param string $content 图片base64内容
+     * @param string $dirname 图片存储目录
+     * @return string
+     */
+    function base64_image($content, $dirname = '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($dirname . 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 (AdminService::instance()->check()) {
+        return $next($request);
+    } elseif (AdminService::instance()->isLogin()) {
+        return json(['code' => 0, 'msg' => '抱歉,没有访问该操作的权限!']);
+    } else {
+        return json(['code' => 0, 'msg' => '抱歉,需要登录获取访问权限!', 'url' => url('@admin/login')]);
+    }
+});
+
+// ThinkAdmin 图形验证码
+Route::get('/think/admin/captcha', function () {
+    $image = CaptchaService::instance();
+    return json(['code' => '1', 'info' => '生成验证码', 'data' => [
+        'uniqid' => $image->getUniqid(), 'image' => $image->getData()
+    ]]);
+});

+ 3659 - 0
application/admin/view/api/plugs/icon.html

@@ -0,0 +1,3659 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="utf-8">
+    <title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
+    <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=1">
+    <link href="__ROOT__/static/plugs/awesome/fonts.css?v={:date('ymd')}" rel="stylesheet">
+    <link href="__ROOT__/static/plugs/layui/css/layui.css?v={:date('ymd')}" rel="stylesheet">
+
+    <style>
+        ::-webkit-input-placeholder {
+            color: #aaa
+        }
+
+        ::-webkit-scrollbar {
+            width: 3px;
+            height: 3px
+        }
+
+        ::-webkit-scrollbar-track {
+            background: #ccc
+        }
+
+        ::-webkit-scrollbar-thumb {
+            background-color: #666
+        }
+
+        ::selection {
+            background-color: #ec494e;
+            color: #fff
+        }
+
+        ::-moz-selection {
+            background-color: #ec494e;
+            color: #fff
+        }
+
+        :-webkit-autofill {
+            -webkit-box-shadow: 0 0 0 1000px white inset;
+            -webkit-text-fill-color: #333
+        }
+
+        ul li {
+            width: 20%;
+            height: 65px;
+            display: block;
+            float: left;
+            margin-right: -1px;
+            margin-left: -2px;
+            margin-bottom: -2px;
+            cursor: pointer;
+            font-size: 14px;
+            overflow: hidden;
+            text-align: center;
+            padding: 15px 0 10px 0;
+            border: 1px solid #e2e2e2;
+            background-color: #efefef;
+            user-select: none;
+            -ms-user-select: none;
+            -moz-user-select: none;
+            -webkit-user-select: none;
+            transition: all .2s linear;
+            -o-transition: all .2s linear;
+            -moz-transition: all .2s linear;
+            -webkit-transition: all .2s linear
+        }
+
+        ul li:hover {
+            color: #fff;
+            background-color: #563d7c
+        }
+
+        ul li:hover i, ul li:hover div {
+            color: #fff;
+        }
+
+        ul li i {
+            color: #333;
+            display: inline-block;
+            font-size: 30px !important
+        }
+
+        ul li div {
+            color: #333;
+            height: 35px;
+            font-size: 13px;
+            line-height: 35px;
+            white-space: nowrap
+        }
+    </style>
+</head>
+<body>
+<ul class="site-doc-icon">
+    <li>
+        <i class="layui-icon layui-icon-rate-half"></i>
+        <div class="icon-title">layui-icon-rate-half</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rate"></i>
+        <div class="icon-title">layui-icon-rate</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rate-solid"></i>
+        <div class="icon-title">layui-icon-rate-solid</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cellphone"></i>
+        <div class="icon-title">layui-icon-cellphone</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-vercode"></i>
+        <div class="icon-title">layui-icon-vercode</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-wechat"></i>
+        <div class="icon-title">layui-icon-login-wechat</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-qq"></i>
+        <div class="icon-title">layui-icon-login-qq</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-login-weibo"></i>
+        <div class="icon-title">layui-icon-login-weibo</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-password"></i>
+        <div class="icon-title">layui-icon-password</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-username"></i>
+        <div class="icon-title">layui-icon-username</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh-3"></i>
+        <div class="icon-title">layui-icon-refresh-3</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-auz"></i>
+        <div class="icon-title">layui-icon-auz</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-spread-left"></i>
+        <div class="icon-title">layui-icon-spread-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-shrink-right"></i>
+        <div class="icon-title">layui-icon-shrink-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-snowflake"></i>
+        <div class="icon-title">layui-icon-snowflake</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tips"></i>
+        <div class="icon-title">layui-icon-tips</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-note"></i>
+        <div class="icon-title">layui-icon-note</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-home"></i>
+        <div class="icon-title">layui-icon-home</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-senior"></i>
+        <div class="icon-title">layui-icon-senior</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh"></i>
+        <div class="icon-title">layui-icon-refresh</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-refresh-1"></i>
+        <div class="icon-title">layui-icon-refresh-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-flag"></i>
+        <div class="icon-title">layui-icon-flag</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-theme"></i>
+        <div class="icon-title">layui-icon-theme</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-notice"></i>
+        <div class="icon-title">layui-icon-notice</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-website"></i>
+        <div class="icon-title">layui-icon-website</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-console"></i>
+        <div class="icon-title">layui-icon-console</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-surprised"></i>
+        <div class="icon-title">layui-icon-face-surprised</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set"></i>
+        <div class="icon-title">layui-icon-set</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-template-1"></i>
+        <div class="icon-title">layui-icon-template-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-app"></i>
+        <div class="icon-title">layui-icon-app</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-template"></i>
+        <div class="icon-title">layui-icon-template</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-praise"></i>
+        <div class="icon-title">layui-icon-praise</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tread"></i>
+        <div class="icon-title">layui-icon-tread</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-male"></i>
+        <div class="icon-title">layui-icon-male</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-female"></i>
+        <div class="icon-title">layui-icon-female</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-camera"></i>
+        <div class="icon-title">layui-icon-camera</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-camera-fill"></i>
+        <div class="icon-title">layui-icon-camera-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-more"></i>
+        <div class="icon-title">layui-icon-more</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-more-vertical"></i>
+        <div class="icon-title">layui-icon-more-vertical</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-rmb"></i>
+        <div class="icon-title">layui-icon-rmb</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-dollar"></i>
+        <div class="icon-title">layui-icon-dollar</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-diamond"></i>
+        <div class="icon-title">layui-icon-diamond</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fire"></i>
+        <div class="icon-title">layui-icon-fire</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-return"></i>
+        <div class="icon-title">layui-icon-return</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-location"></i>
+        <div class="icon-title">layui-icon-location</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-read"></i>
+        <div class="icon-title">layui-icon-read</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-survey"></i>
+        <div class="icon-title">layui-icon-survey</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile"></i>
+        <div class="icon-title">layui-icon-face-smile</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-cry"></i>
+        <div class="icon-title">layui-icon-face-cry</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cart-simple"></i>
+        <div class="icon-title">layui-icon-cart-simple</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cart"></i>
+        <div class="icon-title">layui-icon-cart</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-next"></i>
+        <div class="icon-title">layui-icon-next</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-prev"></i>
+        <div class="icon-title">layui-icon-prev</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload-drag"></i>
+        <div class="icon-title">layui-icon-upload-drag</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload"></i>
+        <div class="icon-title">layui-icon-upload</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-download-circle"></i>
+        <div class="icon-title">layui-icon-download-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-component"></i>
+        <div class="icon-title">layui-icon-component</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-file-b"></i>
+        <div class="icon-title">layui-icon-file-b</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-user"></i>
+        <div class="icon-title">layui-icon-user</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-find-fill"></i>
+        <div class="icon-title">layui-icon-find-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-loading layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
+        <div class="icon-title">layui-icon-loading</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-loading-1 layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>
+        <div class="icon-title">layui-icon-loading-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-1"></i>
+        <div class="icon-title">layui-icon-add-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-play"></i>
+        <div class="icon-title">layui-icon-play</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-pause"></i>
+        <div class="icon-title">layui-icon-pause</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-headset"></i>
+        <div class="icon-title">layui-icon-headset</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-video"></i>
+        <div class="icon-title">layui-icon-video</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-voice"></i>
+        <div class="icon-title">layui-icon-voice</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-speaker"></i>
+        <div class="icon-title">layui-icon-speaker</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-del"></i>
+        <div class="icon-title">layui-icon-fonts-del</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-code"></i>
+        <div class="icon-title">layui-icon-fonts-code</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-html"></i>
+        <div class="icon-title">layui-icon-fonts-html</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-strong"></i>
+        <div class="icon-title">layui-icon-fonts-strong</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-unlink"></i>
+        <div class="icon-title">layui-icon-unlink</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-picture"></i>
+        <div class="icon-title">layui-icon-picture</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-link"></i>
+        <div class="icon-title">layui-icon-link</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile-b"></i>
+        <div class="icon-title">layui-icon-face-smile-b</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-left"></i>
+        <div class="icon-title">layui-icon-align-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-right"></i>
+        <div class="icon-title">layui-icon-align-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-align-center"></i>
+        <div class="icon-title">layui-icon-align-center</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-u"></i>
+        <div class="icon-title">layui-icon-fonts-u</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-i"></i>
+        <div class="icon-title">layui-icon-fonts-i</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tabs"></i>
+        <div class="icon-title">layui-icon-tabs</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-radio"></i>
+        <div class="icon-title">layui-icon-radio</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-circle"></i>
+        <div class="icon-title">layui-icon-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-edit"></i>
+        <div class="icon-title">layui-icon-edit</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-share"></i>
+        <div class="icon-title">layui-icon-share</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-delete"></i>
+        <div class="icon-title">layui-icon-delete</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-form"></i>
+        <div class="icon-title">layui-icon-form</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-cellphone-fine"></i>
+        <div class="icon-title">layui-icon-cellphone-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-dialogue"></i>
+        <div class="icon-title">layui-icon-dialogue</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-fonts-clear"></i>
+        <div class="icon-title">layui-icon-fonts-clear</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-layer"></i>
+        <div class="icon-title">layui-icon-layer</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-date"></i>
+        <div class="icon-title">layui-icon-date</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-water"></i>
+        <div class="icon-title">layui-icon-water</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-code-circle"></i>
+        <div class="icon-title">layui-icon-code-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-carousel"></i>
+        <div class="icon-title">layui-icon-carousel</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-prev-circle"></i>
+        <div class="icon-title">layui-icon-prev-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-layouts"></i>
+        <div class="icon-title">layui-icon-layouts</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-util"></i>
+        <div class="icon-title">layui-icon-util</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-templeate-1"></i>
+        <div class="icon-title">layui-icon-templeate-1</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-upload-circle"></i>
+        <div class="icon-title">layui-icon-upload-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-tree"></i>
+        <div class="icon-title">layui-icon-tree</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-table"></i>
+        <div class="icon-title">layui-icon-table</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chart"></i>
+        <div class="icon-title">layui-icon-chart</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chart-screen"></i>
+        <div class="icon-title">layui-icon-chart-screen</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-engine"></i>
+        <div class="icon-title">layui-icon-engine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-triangle-d"></i>
+        <div class="icon-title">layui-icon-triangle-d</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-triangle-r"></i>
+        <div class="icon-title">layui-icon-triangle-r</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-file"></i>
+        <div class="icon-title">layui-icon-file</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set-sm"></i>
+        <div class="icon-title">layui-icon-set-sm</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-circle"></i>
+        <div class="icon-title">layui-icon-add-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-404"></i>
+        <div class="icon-title">layui-icon-404</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-about"></i>
+        <div class="icon-title">layui-icon-about</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-up"></i>
+        <div class="icon-title">layui-icon-up</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-down"></i>
+        <div class="icon-title">layui-icon-down</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-left"></i>
+        <div class="icon-title">layui-icon-left</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-right"></i>
+        <div class="icon-title">layui-icon-right</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-circle-dot"></i>
+        <div class="icon-title">layui-icon-circle-dot</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-search"></i>
+        <div class="icon-title">layui-icon-search</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-set-fill"></i>
+        <div class="icon-title">layui-icon-set-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-group"></i>
+        <div class="icon-title">layui-icon-group</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-friends"></i>
+        <div class="icon-title">layui-icon-friends</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-reply-fill"></i>
+        <div class="icon-title">layui-icon-reply-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-menu-fill"></i>
+        <div class="icon-title">layui-icon-menu-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-log"></i>
+        <div class="icon-title">layui-icon-log</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-picture-fine"></i>
+        <div class="icon-title">layui-icon-picture-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-face-smile-fine"></i>
+        <div class="icon-title">layui-icon-face-smile-fine</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-list"></i>
+        <div class="icon-title">layui-icon-list</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-release"></i>
+        <div class="icon-title">layui-icon-release</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-ok"></i>
+        <div class="icon-title">layui-icon-ok</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-help"></i>
+        <div class="icon-title">layui-icon-help</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-chat"></i>
+        <div class="icon-title">layui-icon-chat</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-top"></i>
+        <div class="icon-title">layui-icon-top</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-star"></i>
+        <div class="icon-title">layui-icon-star</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-star-fill"></i>
+        <div class="icon-title">layui-icon-star-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-close-fill"></i>
+        <div class="icon-title">layui-icon-close-fill</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-close"></i>
+        <div class="icon-title">layui-icon-close</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-ok-circle"></i>
+        <div class="icon-title">layui-icon-ok-circle</div>
+    </li>
+    <li>
+        <i class="layui-icon layui-icon-add-circle-fine"></i>
+        <div class="icon-title">layui-icon-add-circle-fine</div>
+    </li>
+</ul>
+<ul>
+    <li>
+        <i class="fa fa-address-book"></i>
+        <div class="icon-title">fa-address-book</div>
+    </li>
+    <li>
+        <i class="fa fa-address-book-o"></i>
+        <div class="icon-title">fa-address-book-o</div>
+    </li>
+    <li>
+        <i class="fa fa-address-card"></i>
+        <div class="icon-title">fa-address-card</div>
+    </li>
+    <li>
+        <i class="fa fa-address-card-o"></i>
+        <div class="icon-title">fa-address-card-o</div>
+    </li>
+    <li>
+        <i class="fa fa-adjust"></i>
+        <div class="icon-title">fa-adjust</div>
+    </li>
+    <li>
+        <i class="fa fa-american-sign-language-interpreting"></i>
+        <div class="icon-title">fa-american-sign-language-interpreting</div>
+    </li>
+    <li>
+        <i class="fa fa-anchor"></i>
+        <div class="icon-title">fa-anchor</div>
+    </li>
+    <li>
+        <i class="fa fa-archive"></i>
+        <div class="icon-title">fa-archive</div>
+    </li>
+    <li>
+        <i class="fa fa-area-chart"></i>
+        <div class="icon-title">fa-area-chart</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows"></i>
+        <div class="icon-title">fa-arrows</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows-h"></i>
+        <div class="icon-title">fa-arrows-h</div>
+    </li>
+    <li>
+        <i class="fa fa-arrows-v"></i>
+        <div class="icon-title">fa-arrows-v</div>
+    </li>
+    <li>
+        <i class="fa fa-asl-interpreting"></i>
+        <div class="icon-title">fa-asl-interpreting</div>
+    </li>
+    <li>
+        <i class="fa fa-assistive-listening-systems"></i>
+        <div class="icon-title">fa-assistive-listening-systems</div>
+    </li>
+    <li>
+        <i class="fa fa-asterisk"></i>
+        <div class="icon-title">fa-asterisk</div>
+    </li>
+    <li>
+        <i class="fa fa-at"></i>
+        <div class="icon-title">fa-at</div>
+    </li>
+    <li>
+        <i class="fa fa-audio-description"></i>
+        <div class="icon-title">fa-audio-description</div>
+    </li>
+    <li>
+        <i class="fa fa-automobile"></i>
+        <div class="icon-title">fa-automobile</div>
+    </li>
+    <li>
+        <i class="fa fa-balance-scale"></i>
+        <div class="icon-title">fa-balance-scale</div>
+    </li>
+    <li>
+        <i class="fa fa-ban"></i>
+        <div class="icon-title">fa-ban</div>
+    </li>
+    <li>
+        <i class="fa fa-bank"></i>
+        <div class="icon-title">fa-bank</div>
+    </li>
+    <li>
+        <i class="fa fa-bar-chart"></i>
+        <div class="icon-title">fa-bar-chart</div>
+    </li>
+    <li>
+        <i class="fa fa-bar-chart-o"></i>
+        <div class="icon-title">fa-bar-chart-o</div>
+    </li>
+    <li>
+        <i class="fa fa-barcode"></i>
+        <div class="icon-title">fa-barcode</div>
+    </li>
+    <li>
+        <i class="fa fa-bars"></i>
+        <div class="icon-title">fa-bars</div>
+    </li>
+    <li>
+        <i class="fa fa-bath"></i>
+        <div class="icon-title">fa-bath</div>
+    </li>
+    <li>
+        <i class="fa fa-bathtub"></i>
+        <div class="icon-title">fa-bathtub</div>
+    </li>
+    <li>
+        <i class="fa fa-battery"></i>
+        <div class="icon-title">fa-battery</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-0"></i>
+        <div class="icon-title">fa-battery-0</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-1"></i>
+        <div class="icon-title">fa-battery-1</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-2"></i>
+        <div class="icon-title">fa-battery-2</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-3"></i>
+        <div class="icon-title">fa-battery-3</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-4"></i>
+        <div class="icon-title">fa-battery-4</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-empty"></i>
+        <div class="icon-title">fa-battery-empty</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-full"></i>
+        <div class="icon-title">fa-battery-full</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-half"></i>
+        <div class="icon-title">fa-battery-half</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-quarter"></i>
+        <div class="icon-title">fa-battery-quarter</div>
+    </li>
+    <li>
+        <i class="fa fa-battery-three-quarters"></i>
+        <div class="icon-title">fa-battery-three-quarters</div>
+    </li>
+    <li>
+        <i class="fa fa-bed"></i>
+        <div class="icon-title">fa-bed</div>
+    </li>
+    <li>
+        <i class="fa fa-beer"></i>
+        <div class="icon-title">fa-beer</div>
+    </li>
+    <li>
+        <i class="fa fa-bell"></i>
+        <div class="icon-title">fa-bell</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-o"></i>
+        <div class="icon-title">fa-bell-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-slash"></i>
+        <div class="icon-title">fa-bell-slash</div>
+    </li>
+    <li>
+        <i class="fa fa-bell-slash-o"></i>
+        <div class="icon-title">fa-bell-slash-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bicycle"></i>
+        <div class="icon-title">fa-bicycle</div>
+    </li>
+    <li>
+        <i class="fa fa-binoculars"></i>
+        <div class="icon-title">fa-binoculars</div>
+    </li>
+    <li>
+        <i class="fa fa-birthday-cake"></i>
+        <div class="icon-title">fa-birthday-cake</div>
+    </li>
+    <li>
+        <i class="fa fa-blind"></i>
+        <div class="icon-title">fa-blind</div>
+    </li>
+    <li>
+        <i class="fa fa-bluetooth"></i>
+        <div class="icon-title">fa-bluetooth</div>
+    </li>
+    <li>
+        <i class="fa fa-bluetooth-b"></i>
+        <div class="icon-title">fa-bluetooth-b</div>
+    </li>
+    <li>
+        <i class="fa fa-bolt"></i>
+        <div class="icon-title">fa-bolt</div>
+    </li>
+    <li>
+        <i class="fa fa-bomb"></i>
+        <div class="icon-title">fa-bomb</div>
+    </li>
+    <li>
+        <i class="fa fa-book"></i>
+        <div class="icon-title">fa-book</div>
+    </li>
+    <li>
+        <i class="fa fa-bookmark"></i>
+        <div class="icon-title">fa-bookmark</div>
+    </li>
+    <li>
+        <i class="fa fa-bookmark-o"></i>
+        <div class="icon-title">fa-bookmark-o</div>
+    </li>
+    <li>
+        <i class="fa fa-braille"></i>
+        <div class="icon-title">fa-braille</div>
+    </li>
+    <li>
+        <i class="fa fa-briefcase"></i>
+        <div class="icon-title">fa-briefcase</div>
+    </li>
+    <li>
+        <i class="fa fa-bug"></i>
+        <div class="icon-title">fa-bug</div>
+    </li>
+    <li>
+        <i class="fa fa-building"></i>
+        <div class="icon-title">fa-building</div>
+    </li>
+    <li>
+        <i class="fa fa-building-o"></i>
+        <div class="icon-title">fa-building-o</div>
+    </li>
+    <li>
+        <i class="fa fa-bullhorn"></i>
+        <div class="icon-title">fa-bullhorn</div>
+    </li>
+    <li>
+        <i class="fa fa-bullseye"></i>
+        <div class="icon-title">fa-bullseye</div>
+    </li>
+    <li>
+        <i class="fa fa-bus"></i>
+        <div class="icon-title">fa-bus</div>
+    </li>
+    <li>
+        <i class="fa fa-cab"></i>
+        <div class="icon-title">fa-cab</div>
+    </li>
+    <li>
+        <i class="fa fa-calculator"></i>
+        <div class="icon-title">fa-calculator</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar"></i>
+        <div class="icon-title">fa-calendar</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-check-o"></i>
+        <div class="icon-title">fa-calendar-check-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-minus-o"></i>
+        <div class="icon-title">fa-calendar-minus-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-o"></i>
+        <div class="icon-title">fa-calendar-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-plus-o"></i>
+        <div class="icon-title">fa-calendar-plus-o</div>
+    </li>
+    <li>
+        <i class="fa fa-calendar-times-o"></i>
+        <div class="icon-title">fa-calendar-times-o</div>
+    </li>
+    <li>
+        <i class="fa fa-camera"></i>
+        <div class="icon-title">fa-camera</div>
+    </li>
+    <li>
+        <i class="fa fa-camera-retro"></i>
+        <div class="icon-title">fa-camera-retro</div>
+    </li>
+    <li>
+        <i class="fa fa-car"></i>
+        <div class="icon-title">fa-car</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-down"></i>
+        <div class="icon-title">fa-caret-square-o-down</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-left"></i>
+        <div class="icon-title">fa-caret-square-o-left</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-right"></i>
+        <div class="icon-title">fa-caret-square-o-right</div>
+    </li>
+    <li>
+        <i class="fa fa-caret-square-o-up"></i>
+        <div class="icon-title">fa-caret-square-o-up</div>
+    </li>
+    <li>
+        <i class="fa fa-cart-arrow-down"></i>
+        <div class="icon-title">fa-cart-arrow-down</div>
+    </li>
+    <li>
+        <i class="fa fa-cart-plus"></i>
+        <div class="icon-title">fa-cart-plus</div>
+    </li>
+    <li>
+        <i class="fa fa-cc"></i>
+        <div class="icon-title">fa-cc</div>
+    </li>
+    <li>
+        <i class="fa fa-certificate"></i>
+        <div class="icon-title">fa-certificate</div>
+    </li>
+    <li>
+        <i class="fa fa-check"></i>
+        <div class="icon-title">fa-check</div>
+    </li>
+    <li>
+        <i class="fa fa-check-circle"></i>
+        <div class="icon-title">fa-check-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-check-circle-o"></i>
+        <div class="icon-title">fa-check-circle-o</div>
+    </li>
+    <li>
+        <i class="fa fa-check-square"></i>
+        <div class="icon-title">fa-check-square</div>
+    </li>
+    <li>
+        <i class="fa fa-check-square-o"></i>
+        <div class="icon-title">fa-check-square-o</div>
+    </li>
+    <li>
+        <i class="fa fa-child"></i>
+        <div class="icon-title">fa-child</div>
+    </li>
+    <li>
+        <i class="fa fa-circle"></i>
+        <div class="icon-title">fa-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-o"></i>
+        <div class="icon-title">fa-circle-o</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-o-notch"></i>
+        <div class="icon-title">fa-circle-o-notch</div>
+    </li>
+    <li>
+        <i class="fa fa-circle-thin"></i>
+        <div class="icon-title">fa-circle-thin</div>
+    </li>
+    <li>
+        <i class="fa fa-clock-o"></i>
+        <div class="icon-title">fa-clock-o</div>
+    </li>
+    <li>
+        <i class="fa fa-clone"></i>
+        <div class="icon-title">fa-clone</div>
+    </li>
+    <li>
+        <i class="fa fa-close"></i>
+        <div class="icon-title">fa-close</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud"></i>
+        <div class="icon-title">fa-cloud</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud-download"></i>
+        <div class="icon-title">fa-cloud-download</div>
+    </li>
+    <li>
+        <i class="fa fa-cloud-upload"></i>
+        <div class="icon-title">fa-cloud-upload</div>
+    </li>
+    <li>
+        <i class="fa fa-code"></i>
+        <div class="icon-title">fa-code</div>
+    </li>
+    <li>
+        <i class="fa fa-code-fork"></i>
+        <div class="icon-title">fa-code-fork</div>
+    </li>
+    <li>
+        <i class="fa fa-coffee"></i>
+        <div class="icon-title">fa-coffee</div>
+    </li>
+    <li>
+        <i class="fa fa-cog"></i>
+        <div class="icon-title">fa-cog</div>
+    </li>
+    <li>
+        <i class="fa fa-cogs"></i>
+        <div class="icon-title">fa-cogs</div>
+    </li>
+    <li>
+        <i class="fa fa-comment"></i>
+        <div class="icon-title">fa-comment</div>
+    </li>
+    <li>
+        <i class="fa fa-comment-o"></i>
+        <div class="icon-title">fa-comment-o</div>
+    </li>
+    <li>
+        <i class="fa fa-commenting"></i>
+        <div class="icon-title">fa-commenting</div>
+    </li>
+    <li>
+        <i class="fa fa-commenting-o"></i>
+        <div class="icon-title">fa-commenting-o</div>
+    </li>
+    <li>
+        <i class="fa fa-comments"></i>
+        <div class="icon-title">fa-comments</div>
+    </li>
+    <li>
+        <i class="fa fa-comments-o"></i>
+        <div class="icon-title">fa-comments-o</div>
+    </li>
+    <li>
+        <i class="fa fa-compass"></i>
+        <div class="icon-title">fa-compass</div>
+    </li>
+    <li>
+        <i class="fa fa-copyright"></i>
+        <div class="icon-title">fa-copyright</div>
+    </li>
+    <li>
+        <i class="fa fa-creative-commons"></i>
+        <div class="icon-title">fa-creative-commons</div>
+    </li>
+    <li>
+        <i class="fa fa-credit-card"></i>
+        <div class="icon-title">fa-credit-card</div>
+    </li>
+    <li><i class="fa fa-credit-card-alt"></i>
+        <div class="icon-title">fa-credit-card-alt</div>
+    </li>
+    <li><i class="fa fa-crop"></i>
+        <div class="icon-title">fa-crop</div>
+    </li>
+    <li><i class="fa fa-crosshairs"></i>
+        <div class="icon-title">fa-crosshairs</div>
+    </li>
+    <li><i class="fa fa-cube"></i>
+        <div class="icon-title">fa-cube</div>
+    </li>
+    <li><i class="fa fa-cubes"></i>
+        <div class="icon-title">fa-cubes</div>
+    </li>
+    <li><i class="fa fa-cutlery"></i>
+        <div class="icon-title">fa-cutlery</div>
+    </li>
+    <li><i class="fa fa-dashboard"></i>
+        <div class="icon-title">fa-dashboard</div>
+    </li>
+    <li><i class="fa fa-database"></i>
+        <div class="icon-title">fa-database</div>
+    </li>
+    <li><i class="fa fa-deaf"></i>
+        <div class="icon-title">fa-deaf</div>
+    </li>
+    <li><i class="fa fa-deafness"></i>
+        <div class="icon-title">fa-deafness</div>
+    </li>
+    <li><i class="fa fa-desktop"></i>
+        <div class="icon-title">fa-desktop</div>
+    </li>
+    <li><i class="fa fa-diamond"></i>
+        <div class="icon-title">fa-diamond</div>
+    </li>
+    <li><i class="fa fa-dot-circle-o"></i>
+        <div class="icon-title">fa-dot-circle-o</div>
+    </li>
+    <li><i class="fa fa-download"></i>
+        <div class="icon-title">fa-download</div>
+    </li>
+    <li><i class="fa fa-drivers-license"></i>
+        <div class="icon-title">fa-drivers-license</div>
+    </li>
+    <li><i class="fa fa-drivers-license-o"></i>
+        <div class="icon-title">fa-drivers-license-o</div>
+    </li>
+    <li><i class="fa fa-edit"></i>
+        <div class="icon-title">fa-edit</div>
+    </li>
+    <li><i class="fa fa-ellipsis-h"></i>
+        <div class="icon-title">fa-ellipsis-h</div>
+    </li>
+    <li><i class="fa fa-ellipsis-v"></i>
+        <div class="icon-title">fa-ellipsis-v</div>
+    </li>
+    <li><i class="fa fa-envelope"></i>
+        <div class="icon-title">fa-envelope</div>
+    </li>
+    <li><i class="fa fa-envelope-o"></i>
+        <div class="icon-title">fa-envelope-o</div>
+    </li>
+    <li><i class="fa fa-envelope-open"></i>
+        <div class="icon-title">fa-envelope-open</div>
+    </li>
+    <li><i class="fa fa-envelope-open-o"></i>
+        <div class="icon-title">fa-envelope-open-o</div>
+    </li>
+    <li><i class="fa fa-envelope-square"></i>
+        <div class="icon-title">fa-envelope-square</div>
+    </li>
+    <li><i class="fa fa-eraser"></i>
+        <div class="icon-title">fa-eraser</div>
+    </li>
+    <li><i class="fa fa-exchange"></i>
+        <div class="icon-title">fa-exchange</div>
+    </li>
+    <li><i class="fa fa-exclamation"></i>
+        <div class="icon-title">fa-exclamation</div>
+    </li>
+    <li><i class="fa fa-exclamation-circle"></i>
+        <div class="icon-title">fa-exclamation-circle</div>
+    </li>
+    <li><i class="fa fa-exclamation-triangle"></i>
+        <div class="icon-title">fa-exclamation-triangle</div>
+    </li>
+    <li><i class="fa fa-external-link"></i>
+        <div class="icon-title">fa-external-link</div>
+    </li>
+    <li><i class="fa fa-external-link-square"></i>
+        <div class="icon-title">fa-external-link-square</div>
+    </li>
+    <li><i class="fa fa-eye"></i>
+        <div class="icon-title">fa-eye</div>
+    </li>
+    <li><i class="fa fa-eye-slash"></i>
+        <div class="icon-title">fa-eye-slash</div>
+    </li>
+    <li><i class="fa fa-eyedropper"></i>
+        <div class="icon-title">fa-eyedropper</div>
+    </li>
+    <li><i class="fa fa-fax"></i>
+        <div class="icon-title">fa-fax</div>
+    </li>
+    <li><i class="fa fa-feed"></i>
+        <div class="icon-title">fa-feed</div>
+    </li>
+    <li><i class="fa fa-female"></i>
+        <div class="icon-title">fa-female</div>
+    </li>
+    <li><i class="fa fa-fighter-jet"></i>
+        <div class="icon-title">fa-fighter-jet</div>
+    </li>
+    <li><i class="fa fa-file-archive-o"></i>
+        <div class="icon-title">fa-file-archive-o</div>
+    </li>
+    <li><i class="fa fa-file-audio-o"></i>
+        <div class="icon-title">fa-file-audio-o</div>
+    </li>
+    <li><i class="fa fa-file-code-o"></i>
+        <div class="icon-title">fa-file-code-o</div>
+    </li>
+    <li><i class="fa fa-file-excel-o"></i>
+        <div class="icon-title">fa-file-excel-o</div>
+    </li>
+    <li><i class="fa fa-file-image-o"></i>
+        <div class="icon-title">fa-file-image-o</div>
+    </li>
+    <li><i class="fa fa-file-movie-o"></i>
+        <div class="icon-title">fa-file-movie-o</div>
+    </li>
+    <li><i class="fa fa-file-pdf-o"></i>
+        <div class="icon-title">fa-file-pdf-o</div>
+    </li>
+    <li><i class="fa fa-file-photo-o"></i>
+        <div class="icon-title">fa-file-photo-o</div>
+    </li>
+    <li><i class="fa fa-file-picture-o"></i>
+        <div class="icon-title">fa-file-picture-o</div>
+    </li>
+    <li><i class="fa fa-file-powerpoint-o"></i>
+        <div class="icon-title">fa-file-powerpoint-o</div>
+    </li>
+    <li><i class="fa fa-file-sound-o"></i>
+        <div class="icon-title">fa-file-sound-o</div>
+    </li>
+    <li><i class="fa fa-file-video-o"></i>
+        <div class="icon-title">fa-file-video-o</div>
+    </li>
+    <li><i class="fa fa-file-word-o"></i>
+        <div class="icon-title">fa-file-word-o</div>
+    </li>
+    <li><i class="fa fa-file-zip-o"></i>
+        <div class="icon-title">fa-file-zip-o</div>
+    </li>
+    <li><i class="fa fa-film"></i>
+        <div class="icon-title">fa-film</div>
+    </li>
+    <li><i class="fa fa-filter"></i>
+        <div class="icon-title">fa-filter</div>
+    </li>
+    <li><i class="fa fa-fire"></i>
+        <div class="icon-title">fa-fire</div>
+    </li>
+    <li><i class="fa fa-fire-extinguisher"></i>
+        <div class="icon-title">fa-fire-extinguisher</div>
+    </li>
+    <li><i class="fa fa-flag"></i>
+        <div class="icon-title">fa-flag</div>
+    </li>
+    <li><i class="fa fa-flag-checkered"></i>
+        <div class="icon-title">fa-flag-checkered</div>
+    </li>
+    <li><i class="fa fa-flag-o"></i>
+        <div class="icon-title">fa-flag-o</div>
+    </li>
+    <li><i class="fa fa-flash"></i>
+        <div class="icon-title">fa-flash</div>
+    </li>
+    <li><i class="fa fa-flask"></i>
+        <div class="icon-title">fa-flask</div>
+    </li>
+    <li><i class="fa fa-folder"></i>
+        <div class="icon-title">fa-folder</div>
+    </li>
+    <li><i class="fa fa-folder-o"></i>
+        <div class="icon-title">fa-folder-o</div>
+    </li>
+    <li><i class="fa fa-folder-open"></i>
+        <div class="icon-title">fa-folder-open</div>
+    </li>
+    <li><i class="fa fa-folder-open-o"></i>
+        <div class="icon-title">fa-folder-open-o</div>
+    </li>
+    <li><i class="fa fa-frown-o"></i>
+        <div class="icon-title">fa-frown-o</div>
+    </li>
+    <li><i class="fa fa-futbol-o"></i>
+        <div class="icon-title">fa-futbol-o</div>
+    </li>
+    <li><i class="fa fa-gamepad"></i>
+        <div class="icon-title">fa-gamepad</div>
+    </li>
+    <li><i class="fa fa-gavel"></i>
+        <div class="icon-title">fa-gavel</div>
+    </li>
+    <li><i class="fa fa-gear"></i>
+        <div class="icon-title">fa-gear</div>
+    </li>
+    <li><i class="fa fa-gears"></i>
+        <div class="icon-title">fa-gears</div>
+    </li>
+    <li><i class="fa fa-gift"></i>
+        <div class="icon-title">fa-gift</div>
+    </li>
+    <li><i class="fa fa-glass"></i>
+        <div class="icon-title">fa-glass</div>
+    </li>
+    <li><i class="fa fa-globe"></i>
+        <div class="icon-title">fa-globe</div>
+    </li>
+    <li><i class="fa fa-graduation-cap"></i>
+        <div class="icon-title">fa-graduation-cap</div>
+    </li>
+    <li><i class="fa fa-group"></i>
+        <div class="icon-title">fa-group</div>
+    </li>
+    <li><i class="fa fa-hand-grab-o"></i>
+        <div class="icon-title">fa-hand-grab-o</div>
+    </li>
+    <li><i class="fa fa-hand-lizard-o"></i>
+        <div class="icon-title">fa-hand-lizard-o</div>
+    </li>
+    <li><i class="fa fa-hand-paper-o"></i>
+        <div class="icon-title">fa-hand-paper-o</div>
+    </li>
+    <li><i class="fa fa-hand-peace-o"></i>
+        <div class="icon-title">fa-hand-peace-o</div>
+    </li>
+    <li><i class="fa fa-hand-pointer-o"></i>
+        <div class="icon-title">fa-hand-pointer-o</div>
+    </li>
+    <li><i class="fa fa-hand-rock-o"></i>
+        <div class="icon-title">fa-hand-rock-o</div>
+    </li>
+    <li><i class="fa fa-hand-scissors-o"></i>
+        <div class="icon-title">fa-hand-scissors-o</div>
+    </li>
+    <li><i class="fa fa-hand-spock-o"></i>
+        <div class="icon-title">fa-hand-spock-o</div>
+    </li>
+    <li><i class="fa fa-hand-stop-o"></i>
+        <div class="icon-title">fa-hand-stop-o</div>
+    </li>
+    <li><i class="fa fa-handshake-o"></i>
+        <div class="icon-title">fa-handshake-o</div>
+    </li>
+    <li><i class="fa fa-hard-of-hearing"></i>
+        <div class="icon-title">fa-hard-of-hearing</div>
+    </li>
+    <li><i class="fa fa-hashtag"></i>
+        <div class="icon-title">fa-hashtag</div>
+    </li>
+    <li><i class="fa fa-hdd-o"></i>
+        <div class="icon-title">fa-hdd-o</div>
+    </li>
+    <li><i class="fa fa-headphones"></i>
+        <div class="icon-title">fa-headphones</div>
+    </li>
+    <li><i class="fa fa-heart"></i>
+        <div class="icon-title">fa-heart</div>
+    </li>
+    <li><i class="fa fa-heart-o"></i>
+        <div class="icon-title">fa-heart-o</div>
+    </li>
+    <li><i class="fa fa-heartbeat"></i>
+        <div class="icon-title">fa-heartbeat</div>
+    </li>
+    <li><i class="fa fa-history"></i>
+        <div class="icon-title">fa-history</div>
+    </li>
+    <li><i class="fa fa-home"></i>
+        <div class="icon-title">fa-home</div>
+    </li>
+    <li><i class="fa fa-hotel"></i>
+        <div class="icon-title">fa-hotel</div>
+    </li>
+    <li><i class="fa fa-hourglass"></i>
+        <div class="icon-title">fa-hourglass</div>
+    </li>
+    <li><i class="fa fa-hourglass-1"></i>
+        <div class="icon-title">fa-hourglass-1</div>
+    </li>
+    <li><i class="fa fa-hourglass-2"></i>
+        <div class="icon-title">fa-hourglass-2</div>
+    </li>
+    <li><i class="fa fa-hourglass-3"></i>
+        <div class="icon-title">fa-hourglass-3</div>
+    </li>
+    <li><i class="fa fa-hourglass-end"></i>
+        <div class="icon-title">fa-hourglass-end</div>
+    </li>
+    <li><i class="fa fa-hourglass-half"></i>
+        <div class="icon-title">fa-hourglass-half</div>
+    </li>
+    <li><i class="fa fa-hourglass-o"></i>
+        <div class="icon-title">fa-hourglass-o</div>
+    </li>
+    <li><i class="fa fa-hourglass-start"></i>
+        <div class="icon-title">fa-hourglass-start</div>
+    </li>
+    <li><i class="fa fa-i-cursor"></i>
+        <div class="icon-title">fa-i-cursor</div>
+    </li>
+    <li><i class="fa fa-id-badge"></i>
+        <div class="icon-title">fa-id-badge</div>
+    </li>
+    <li><i class="fa fa-id-card"></i>
+        <div class="icon-title">fa-id-card</div>
+    </li>
+    <li><i class="fa fa-id-card-o"></i>
+        <div class="icon-title">fa-id-card-o</div>
+    </li>
+    <li><i class="fa fa-image"></i>
+        <div class="icon-title">fa-image</div>
+    </li>
+    <li><i class="fa fa-inbox"></i>
+        <div class="icon-title">fa-inbox</div>
+    </li>
+    <li><i class="fa fa-industry"></i>
+        <div class="icon-title">fa-industry</div>
+    </li>
+    <li><i class="fa fa-info"></i>
+        <div class="icon-title">fa-info</div>
+    </li>
+    <li><i class="fa fa-info-circle"></i>
+        <div class="icon-title">fa-info-circle</div>
+    </li>
+    <li><i class="fa fa-institution"></i>
+        <div class="icon-title">fa-institution</div>
+    </li>
+    <li><i class="fa fa-key"></i>
+        <div class="icon-title">fa-key</div>
+    </li>
+    <li><i class="fa fa-keyboard-o"></i>
+        <div class="icon-title">fa-keyboard-o</div>
+    </li>
+    <li><i class="fa fa-language"></i>
+        <div class="icon-title">fa-language</div>
+    </li>
+    <li><i class="fa fa-laptop"></i>
+        <div class="icon-title">fa-laptop</div>
+    </li>
+    <li><i class="fa fa-leaf"></i>
+        <div class="icon-title">fa-leaf</div>
+    </li>
+    <li><i class="fa fa-legal"></i>
+        <div class="icon-title">fa-legal</div>
+    </li>
+    <li><i class="fa fa-lemon-o"></i>
+        <div class="icon-title">fa-lemon-o</div>
+    </li>
+    <li><i class="fa fa-level-down"></i>
+        <div class="icon-title">fa-level-down</div>
+    </li>
+    <li><i class="fa fa-level-up"></i>
+        <div class="icon-title">fa-level-up</div>
+    </li>
+    <li><i class="fa fa-life-bouy"></i>
+        <div class="icon-title">fa-life-bouy</div>
+    </li>
+    <li><i class="fa fa-life-buoy"></i>
+        <div class="icon-title">fa-life-buoy</div>
+    </li>
+    <li><i class="fa fa-life-ring"></i>
+        <div class="icon-title">fa-life-ring</div>
+    </li>
+    <li><i class="fa fa-life-saver"></i>
+        <div class="icon-title">fa-life-saver</div>
+    </li>
+    <li><i class="fa fa-lightbulb-o"></i>
+        <div class="icon-title">fa-lightbulb-o</div>
+    </li>
+    <li><i class="fa fa-line-chart"></i>
+        <div class="icon-title">fa-line-chart</div>
+    </li>
+    <li><i class="fa fa-location-arrow"></i>
+        <div class="icon-title">fa-location-arrow</div>
+    </li>
+    <li><i class="fa fa-lock"></i>
+        <div class="icon-title">fa-lock</div>
+    </li>
+    <li><i class="fa fa-low-vision"></i>
+        <div class="icon-title">fa-low-vision</div>
+    </li>
+    <li><i class="fa fa-magic"></i>
+        <div class="icon-title">fa-magic</div>
+    </li>
+    <li><i class="fa fa-magnet"></i>
+        <div class="icon-title">fa-magnet</div>
+    </li>
+    <li><i class="fa fa-mail-forward"></i>
+        <div class="icon-title">fa-mail-forward</div>
+    </li>
+    <li><i class="fa fa-mail-reply"></i>
+        <div class="icon-title">fa-mail-reply</div>
+    </li>
+    <li><i class="fa fa-mail-reply-all"></i>
+        <div class="icon-title">fa-mail-reply-all</div>
+    </li>
+    <li><i class="fa fa-male"></i>
+        <div class="icon-title">fa-male</div>
+    </li>
+    <li><i class="fa fa-map"></i>
+        <div class="icon-title">fa-map</div>
+    </li>
+    <li><i class="fa fa-map-marker"></i>
+        <div class="icon-title">fa-map-marker</div>
+    </li>
+    <li><i class="fa fa-map-o"></i>
+        <div class="icon-title">fa-map-o</div>
+    </li>
+    <li><i class="fa fa-map-pin"></i>
+        <div class="icon-title">fa-map-pin</div>
+    </li>
+    <li><i class="fa fa-map-signs"></i>
+        <div class="icon-title">fa-map-signs</div>
+    </li>
+    <li><i class="fa fa-meh-o"></i>
+        <div class="icon-title">fa-meh-o</div>
+    </li>
+    <li><i class="fa fa-microchip"></i>
+        <div class="icon-title">fa-microchip</div>
+    </li>
+    <li><i class="fa fa-microphone"></i>
+        <div class="icon-title">fa-microphone</div>
+    </li>
+    <li><i class="fa fa-microphone-slash"></i>
+        <div class="icon-title">fa-microphone-slash</div>
+    </li>
+    <li><i class="fa fa-minus"></i>
+        <div class="icon-title">fa-minus</div>
+    </li>
+    <li><i class="fa fa-minus-circle"></i>
+        <div class="icon-title">fa-minus-circle</div>
+    </li>
+    <li><i class="fa fa-minus-square"></i>
+        <div class="icon-title">fa-minus-square</div>
+    </li>
+    <li><i class="fa fa-minus-square-o"></i>
+        <div class="icon-title">fa-minus-square-o</div>
+    </li>
+    <li><i class="fa fa-mobile"></i>
+        <div class="icon-title">fa-mobile</div>
+    </li>
+    <li><i class="fa fa-mobile-phone"></i>
+        <div class="icon-title">fa-mobile-phone</div>
+    </li>
+    <li><i class="fa fa-money"></i>
+        <div class="icon-title">fa-money</div>
+    </li>
+    <li><i class="fa fa-moon-o"></i>
+        <div class="icon-title">fa-moon-o</div>
+    </li>
+    <li><i class="fa fa-mortar-board"></i>
+        <div class="icon-title">fa-mortar-board</div>
+    </li>
+    <li><i class="fa fa-motorcycle"></i>
+        <div class="icon-title">fa-motorcycle</div>
+    </li>
+    <li><i class="fa fa-mouse-pointer"></i>
+        <div class="icon-title">fa-mouse-pointer</div>
+    </li>
+    <li><i class="fa fa-music"></i>
+        <div class="icon-title">fa-music</div>
+    </li>
+    <li><i class="fa fa-navicon"></i>
+        <div class="icon-title">fa-navicon</div>
+    </li>
+    <li><i class="fa fa-newspaper-o"></i>
+        <div class="icon-title">fa-newspaper-o</div>
+    </li>
+    <li><i class="fa fa-object-group"></i>
+        <div class="icon-title">fa-object-group</div>
+    </li>
+    <li><i class="fa fa-object-ungroup"></i>
+        <div class="icon-title">fa-object-ungroup</div>
+    </li>
+    <li><i class="fa fa-paint-brush"></i>
+        <div class="icon-title">fa-paint-brush</div>
+    </li>
+    <li><i class="fa fa-paper-plane"></i>
+        <div class="icon-title">fa-paper-plane</div>
+    </li>
+    <li><i class="fa fa-paper-plane-o"></i>
+        <div class="icon-title">fa-paper-plane-o</div>
+    </li>
+    <li><i class="fa fa-paw"></i>
+        <div class="icon-title">fa-paw</div>
+    </li>
+    <li><i class="fa fa-pencil"></i>
+        <div class="icon-title">fa-pencil</div>
+    </li>
+    <li><i class="fa fa-pencil-square"></i>
+        <div class="icon-title">fa-pencil-square</div>
+    </li>
+    <li><i class="fa fa-pencil-square-o"></i>
+        <div class="icon-title">fa-pencil-square-o</div>
+    </li>
+    <li><i class="fa fa-percent"></i>
+        <div class="icon-title">fa-percent</div>
+    </li>
+    <li><i class="fa fa-phone"></i>
+        <div class="icon-title">fa-phone</div>
+    </li>
+    <li><i class="fa fa-phone-square"></i>
+        <div class="icon-title">fa-phone-square</div>
+    </li>
+    <li><i class="fa fa-photo"></i>
+        <div class="icon-title">fa-photo</div>
+    </li>
+    <li><i class="fa fa-picture-o"></i>
+        <div class="icon-title">fa-picture-o</div>
+    </li>
+    <li><i class="fa fa-pie-chart"></i>
+        <div class="icon-title">fa-pie-chart</div>
+    </li>
+    <li><i class="fa fa-plane"></i>
+        <div class="icon-title">fa-plane</div>
+    </li>
+    <li><i class="fa fa-plug"></i>
+        <div class="icon-title">fa-plug</div>
+    </li>
+    <li><i class="fa fa-plus"></i>
+        <div class="icon-title">fa-plus</div>
+    </li>
+    <li><i class="fa fa-plus-circle"></i>
+        <div class="icon-title">fa-plus-circle</div>
+    </li>
+    <li><i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li><i class="fa fa-plus-square-o"></i>
+        <div class="icon-title">fa-plus-square-o</div>
+    </li>
+    <li><i class="fa fa-podcast"></i>
+        <div class="icon-title">fa-podcast</div>
+    </li>
+    <li><i class="fa fa-power-off"></i>
+        <div class="icon-title">fa-power-off</div>
+    </li>
+    <li><i class="fa fa-print"></i>
+        <div class="icon-title">fa-print</div>
+    </li>
+    <li><i class="fa fa-puzzle-piece"></i>
+        <div class="icon-title">fa-puzzle-piece</div>
+    </li>
+    <li><i class="fa fa-qrcode"></i>
+        <div class="icon-title">fa-qrcode</div>
+    </li>
+    <li><i class="fa fa-question"></i>
+        <div class="icon-title">fa-question</div>
+    </li>
+    <li><i class="fa fa-question-circle"></i>
+        <div class="icon-title">fa-question-circle</div>
+    </li>
+    <li><i class="fa fa-question-circle-o"></i>
+        <div class="icon-title">fa-question-circle-o</div>
+    </li>
+    <li><i class="fa fa-quote-left"></i>
+        <div class="icon-title">fa-quote-left</div>
+    </li>
+    <li><i class="fa fa-quote-right"></i>
+        <div class="icon-title">fa-quote-right</div>
+    </li>
+    <li><i class="fa fa-random"></i>
+        <div class="icon-title">fa-random</div>
+    </li>
+    <li><i class="fa fa-recycle"></i>
+        <div class="icon-title">fa-recycle</div>
+    </li>
+    <li><i class="fa fa-refresh"></i>
+        <div class="icon-title">fa-refresh</div>
+    </li>
+    <li><i class="fa fa-registered"></i>
+        <div class="icon-title">fa-registered</div>
+    </li>
+    <li><i class="fa fa-remove"></i>
+        <div class="icon-title">fa-remove</div>
+    </li>
+    <li><i class="fa fa-reorder"></i>
+        <div class="icon-title">fa-reorder</div>
+    </li>
+    <li><i class="fa fa-reply"></i>
+        <div class="icon-title">fa-reply</div>
+    </li>
+    <li><i class="fa fa-reply-all"></i>
+        <div class="icon-title">fa-reply-all</div>
+    </li>
+    <li><i class="fa fa-retweet"></i>
+        <div class="icon-title">fa-retweet</div>
+    </li>
+    <li><i class="fa fa-road"></i>
+        <div class="icon-title">fa-road</div>
+    </li>
+    <li><i class="fa fa-rocket"></i>
+        <div class="icon-title">fa-rocket</div>
+    </li>
+    <li><i class="fa fa-rss"></i>
+        <div class="icon-title">fa-rss</div>
+    </li>
+    <li><i class="fa fa-rss-square"></i>
+        <div class="icon-title">fa-rss-square</div>
+    </li>
+    <li><i class="fa fa-s15"></i>
+        <div class="icon-title">fa-s15</div>
+    </li>
+    <li><i class="fa fa-search"></i>
+        <div class="icon-title">fa-search</div>
+    </li>
+    <li><i class="fa fa-search-minus"></i>
+        <div class="icon-title">fa-search-minus</div>
+    </li>
+    <li><i class="fa fa-search-plus"></i>
+        <div class="icon-title">fa-search-plus</div>
+    </li>
+    <li><i class="fa fa-send"></i>
+        <div class="icon-title">fa-send</div>
+    </li>
+    <li><i class="fa fa-send-o"></i>
+        <div class="icon-title">fa-send-o</div>
+    </li>
+    <li><i class="fa fa-server"></i>
+        <div class="icon-title">fa-server</div>
+    </li>
+    <li><i class="fa fa-share"></i>
+        <div class="icon-title">fa-share</div>
+    </li>
+    <li><i class="fa fa-share-alt"></i>
+        <div class="icon-title">fa-share-alt</div>
+    </li>
+    <li><i class="fa fa-share-alt-square"></i>
+        <div class="icon-title">fa-share-alt-square</div>
+    </li>
+    <li><i class="fa fa-share-square"></i>
+        <div class="icon-title">fa-share-square</div>
+    </li>
+    <li><i class="fa fa-share-square-o"></i>
+        <div class="icon-title">fa-share-square-o</div>
+    </li>
+    <li><i class="fa fa-shield"></i>
+        <div class="icon-title">fa-shield</div>
+    </li>
+    <li><i class="fa fa-ship"></i>
+        <div class="icon-title">fa-ship</div>
+    </li>
+    <li><i class="fa fa-shopping-bag"></i>
+        <div class="icon-title">fa-shopping-bag</div>
+    </li>
+    <li><i class="fa fa-shopping-basket"></i>
+        <div class="icon-title">fa-shopping-basket</div>
+    </li>
+    <li><i class="fa fa-shopping-cart"></i>
+        <div class="icon-title">fa-shopping-cart</div>
+    </li>
+    <li><i class="fa fa-shower"></i>
+        <div class="icon-title">fa-shower</div>
+    </li>
+    <li><i class="fa fa-sign-in"></i>
+        <div class="icon-title">fa-sign-in</div>
+    </li>
+    <li><i class="fa fa-sign-language"></i>
+        <div class="icon-title">fa-sign-language</div>
+    </li>
+    <li><i class="fa fa-sign-out"></i>
+        <div class="icon-title">fa-sign-out</div>
+    </li>
+    <li><i class="fa fa-signal"></i>
+        <div class="icon-title">fa-signal</div>
+    </li>
+    <li><i class="fa fa-signing"></i>
+        <div class="icon-title">fa-signing</div>
+    </li>
+    <li><i class="fa fa-sitemap"></i>
+        <div class="icon-title">fa-sitemap</div>
+    </li>
+    <li><i class="fa fa-sliders"></i>
+        <div class="icon-title">fa-sliders</div>
+    </li>
+    <li><i class="fa fa-smile-o"></i>
+        <div class="icon-title">fa-smile-o</div>
+    </li>
+    <li><i class="fa fa-snowflake-o"></i>
+        <div class="icon-title">fa-snowflake-o</div>
+    </li>
+    <li><i class="fa fa-soccer-ball-o"></i>
+        <div class="icon-title">fa-soccer-ball-o</div>
+    </li>
+    <li><i class="fa fa-sort"></i>
+        <div class="icon-title">fa-sort</div>
+    </li>
+    <li><i class="fa fa-sort-alpha-asc"></i>
+        <div class="icon-title">fa-sort-alpha-asc</div>
+    </li>
+    <li><i class="fa fa-sort-alpha-desc"></i>
+        <div class="icon-title">fa-sort-alpha-desc</div>
+    </li>
+    <li><i class="fa fa-sort-amount-asc"></i>
+        <div class="icon-title">fa-sort-amount-asc</div>
+    </li>
+    <li><i class="fa fa-sort-amount-desc"></i>
+        <div class="icon-title">fa-sort-amount-desc</div>
+    </li>
+    <li><i class="fa fa-sort-asc"></i>
+        <div class="icon-title">fa-sort-asc</div>
+    </li>
+    <li><i class="fa fa-sort-desc"></i>
+        <div class="icon-title">fa-sort-desc</div>
+    </li>
+    <li><i class="fa fa-sort-down"></i>
+        <div class="icon-title">fa-sort-down</div>
+    </li>
+    <li><i class="fa fa-sort-numeric-asc"></i>
+        <div class="icon-title">fa-sort-numeric-asc</div>
+    </li>
+    <li><i class="fa fa-sort-numeric-desc"></i>
+        <div class="icon-title">fa-sort-numeric-desc</div>
+    </li>
+    <li><i class="fa fa-sort-up"></i>
+        <div class="icon-title">fa-sort-up</div>
+    </li>
+    <li><i class="fa fa-space-shuttle"></i>
+        <div class="icon-title">fa-space-shuttle</div>
+    </li>
+    <li><i class="fa fa-spinner"></i>
+        <div class="icon-title">fa-spinner</div>
+    </li>
+    <li><i class="fa fa-spoon"></i>
+        <div class="icon-title">fa-spoon</div>
+    </li>
+    <li><i class="fa fa-square"></i>
+        <div class="icon-title">fa-square</div>
+    </li>
+    <li><i class="fa fa-square-o"></i>
+        <div class="icon-title">fa-square-o</div>
+    </li>
+    <li><i class="fa fa-star"></i>
+        <div class="icon-title">fa-star</div>
+    </li>
+    <li><i class="fa fa-star-half"></i>
+        <div class="icon-title">fa-star-half</div>
+    </li>
+    <li><i class="fa fa-star-half-empty"></i>
+        <div class="icon-title">fa-star-half-empty</div>
+    </li>
+    <li><i class="fa fa-star-half-full"></i>
+        <div class="icon-title">fa-star-half-full</div>
+    </li>
+    <li><i class="fa fa-star-half-o"></i>
+        <div class="icon-title">fa-star-half-o</div>
+    </li>
+    <li><i class="fa fa-star-o"></i>
+        <div class="icon-title">fa-star-o</div>
+    </li>
+    <li><i class="fa fa-sticky-note"></i>
+        <div class="icon-title">fa-sticky-note</div>
+    </li>
+    <li><i class="fa fa-sticky-note-o"></i>
+        <div class="icon-title">fa-sticky-note-o</div>
+    </li>
+    <li><i class="fa fa-street-view"></i>
+        <div class="icon-title">fa-street-view</div>
+    </li>
+    <li><i class="fa fa-suitcase"></i>
+        <div class="icon-title">fa-suitcase</div>
+    </li>
+    <li><i class="fa fa-sun-o"></i>
+        <div class="icon-title">fa-sun-o</div>
+    </li>
+    <li><i class="fa fa-support"></i>
+        <div class="icon-title">fa-support</div>
+    </li>
+    <li><i class="fa fa-tablet"></i>
+        <div class="icon-title">fa-tablet</div>
+    </li>
+    <li><i class="fa fa-tachometer"></i>
+        <div class="icon-title">fa-tachometer</div>
+    </li>
+    <li><i class="fa fa-tag"></i>
+        <div class="icon-title">fa-tag</div>
+    </li>
+    <li><i class="fa fa-tags"></i>
+        <div class="icon-title">fa-tags</div>
+    </li>
+    <li><i class="fa fa-tasks"></i>
+        <div class="icon-title">fa-tasks</div>
+    </li>
+    <li><i class="fa fa-taxi"></i>
+        <div class="icon-title">fa-taxi</div>
+    </li>
+    <li><i class="fa fa-television"></i>
+        <div class="icon-title">fa-television</div>
+    </li>
+    <li><i class="fa fa-terminal"></i>
+        <div class="icon-title">fa-terminal</div>
+    </li>
+    <li><i class="fa fa-thermometer"></i>
+        <div class="icon-title">fa-thermometer</div>
+    </li>
+    <li><i class="fa fa-thermometer-0"></i>
+        <div class="icon-title">fa-thermometer-0</div>
+    </li>
+    <li><i class="fa fa-thermometer-1"></i>
+        <div class="icon-title">fa-thermometer-1</div>
+    </li>
+    <li><i class="fa fa-thermometer-2"></i>
+        <div class="icon-title">fa-thermometer-2</div>
+    </li>
+    <li><i class="fa fa-thermometer-3"></i>
+        <div class="icon-title">fa-thermometer-3</div>
+    </li>
+    <li><i class="fa fa-thermometer-4"></i>
+        <div class="icon-title">fa-thermometer-4</div>
+    </li>
+    <li><i class="fa fa-thermometer-empty"></i>
+        <div class="icon-title">fa-thermometer-empty</div>
+    </li>
+    <li><i class="fa fa-thermometer-full"></i>
+        <div class="icon-title">fa-thermometer-full</div>
+    </li>
+    <li><i class="fa fa-thermometer-half"></i>
+        <div class="icon-title">fa-thermometer-half</div>
+    </li>
+    <li><i class="fa fa-thermometer-quarter"></i>
+        <div class="icon-title">fa-thermometer-quarter</div>
+    </li>
+    <li><i class="fa fa-thermometer-three-quarters"></i>
+        <div class="icon-title">fa-thermometer-three-quarters</div>
+    </li>
+    <li><i class="fa fa-thumb-tack"></i>
+        <div class="icon-title">fa-thumb-tack</div>
+    </li>
+    <li><i class="fa fa-thumbs-down"></i>
+        <div class="icon-title">fa-thumbs-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-down"></i>
+        <div class="icon-title">fa-thumbs-o-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-up"></i>
+        <div class="icon-title">fa-thumbs-o-up</div>
+    </li>
+    <li><i class="fa fa-thumbs-up"></i>
+        <div class="icon-title">fa-thumbs-up</div>
+    </li>
+    <li><i class="fa fa-ticket"></i>
+        <div class="icon-title">fa-ticket</div>
+    </li>
+    <li><i class="fa fa-times"></i>
+        <div class="icon-title">fa-times</div>
+    </li>
+    <li><i class="fa fa-times-circle"></i>
+        <div class="icon-title">fa-times-circle</div>
+    </li>
+    <li><i class="fa fa-times-circle-o"></i>
+        <div class="icon-title">fa-times-circle-o</div>
+    </li>
+    <li><i class="fa fa-times-rectangle"></i>
+        <div class="icon-title">fa-times-rectangle</div>
+    </li>
+    <li><i class="fa fa-times-rectangle-o"></i>
+        <div class="icon-title">fa-times-rectangle-o</div>
+    </li>
+    <li><i class="fa fa-tint"></i>
+        <div class="icon-title">fa-tint</div>
+    </li>
+    <li><i class="fa fa-toggle-down"></i>
+        <div class="icon-title">fa-toggle-down</div>
+    </li>
+    <li><i class="fa fa-toggle-left"></i>
+        <div class="icon-title">fa-toggle-left</div>
+    </li>
+    <li><i class="fa fa-toggle-off"></i>
+        <div class="icon-title">fa-toggle-off</div>
+    </li>
+    <li><i class="fa fa-toggle-on"></i>
+        <div class="icon-title">fa-toggle-on</div>
+    </li>
+    <li><i class="fa fa-toggle-right"></i>
+        <div class="icon-title">fa-toggle-right</div>
+    </li>
+    <li><i class="fa fa-toggle-up"></i>
+        <div class="icon-title">fa-toggle-up</div>
+    </li>
+    <li><i class="fa fa-trademark"></i>
+        <div class="icon-title">fa-trademark</div>
+    </li>
+    <li><i class="fa fa-trash"></i>
+        <div class="icon-title">fa-trash</div>
+    </li>
+    <li><i class="fa fa-trash-o"></i>
+        <div class="icon-title">fa-trash-o</div>
+    </li>
+    <li><i class="fa fa-tree"></i>
+        <div class="icon-title">fa-tree</div>
+    </li>
+    <li><i class="fa fa-trophy"></i>
+        <div class="icon-title">fa-trophy</div>
+    </li>
+    <li><i class="fa fa-truck"></i>
+        <div class="icon-title">fa-truck</div>
+    </li>
+    <li><i class="fa fa-tty"></i>
+        <div class="icon-title">fa-tty</div>
+    </li>
+    <li><i class="fa fa-tv"></i>
+        <div class="icon-title">fa-tv</div>
+    </li>
+    <li><i class="fa fa-umbrella"></i>
+        <div class="icon-title">fa-umbrella</div>
+    </li>
+    <li><i class="fa fa-universal-access"></i>
+        <div class="icon-title">fa-universal-access</div>
+    </li>
+    <li><i class="fa fa-university"></i>
+        <div class="icon-title">fa-university</div>
+    </li>
+    <li><i class="fa fa-unlock"></i>
+        <div class="icon-title">fa-unlock</div>
+    </li>
+    <li><i class="fa fa-unlock-alt"></i>
+        <div class="icon-title">fa-unlock-alt</div>
+    </li>
+    <li><i class="fa fa-unsorted"></i>
+        <div class="icon-title">fa-unsorted</div>
+    </li>
+    <li><i class="fa fa-upload"></i>
+        <div class="icon-title">fa-upload</div>
+    </li>
+    <li><i class="fa fa-user"></i>
+        <div class="icon-title">fa-user</div>
+    </li>
+    <li><i class="fa fa-user-circle"></i>
+        <div class="icon-title">fa-user-circle</div>
+    </li>
+    <li><i class="fa fa-user-circle-o"></i>
+        <div class="icon-title">fa-user-circle-o</div>
+    </li>
+    <li><i class="fa fa-user-o"></i>
+        <div class="icon-title">fa-user-o</div>
+    </li>
+    <li><i class="fa fa-user-plus"></i>
+        <div class="icon-title">fa-user-plus</div>
+    </li>
+    <li><i class="fa fa-user-secret"></i>
+        <div class="icon-title">fa-user-secret</div>
+    </li>
+    <li><i class="fa fa-user-times"></i>
+        <div class="icon-title">fa-user-times</div>
+    </li>
+    <li><i class="fa fa-users"></i>
+        <div class="icon-title">fa-users</div>
+    </li>
+    <li><i class="fa fa-vcard"></i>
+        <div class="icon-title">fa-vcard</div>
+    </li>
+    <li><i class="fa fa-vcard-o"></i>
+        <div class="icon-title">fa-vcard-o</div>
+    </li>
+    <li><i class="fa fa-video-camera"></i>
+        <div class="icon-title">fa-video-camera</div>
+    </li>
+    <li><i class="fa fa-volume-control-phone"></i>
+        <div class="icon-title">fa-volume-control-phone</div>
+    </li>
+    <li><i class="fa fa-volume-down"></i>
+        <div class="icon-title">fa-volume-down</div>
+    </li>
+    <li><i class="fa fa-volume-off"></i>
+        <div class="icon-title">fa-volume-off</div>
+    </li>
+    <li><i class="fa fa-volume-up"></i>
+        <div class="icon-title">fa-volume-up</div>
+    </li>
+    <li><i class="fa fa-warning"></i>
+        <div class="icon-title">fa-warning</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-wifi"></i>
+        <div class="icon-title">fa-wifi</div>
+    </li>
+    <li><i class="fa fa-window-close"></i>
+        <div class="icon-title">fa-window-close</div>
+    </li>
+    <li><i class="fa fa-window-close-o"></i>
+        <div class="icon-title">fa-window-close-o</div>
+    </li>
+    <li><i class="fa fa-window-maximize"></i>
+        <div class="icon-title">fa-window-maximize</div>
+    </li>
+    <li><i class="fa fa-window-minimize"></i>
+        <div class="icon-title">fa-window-minimize</div>
+    </li>
+    <li><i class="fa fa-window-restore"></i>
+        <div class="icon-title">fa-window-restore</div>
+    </li>
+    <li><i class="fa fa-wrench"></i>
+        <div class="icon-title">fa-wrench</div>
+    </li>
+    <li><i class="fa fa-american-sign-language-interpreting"></i>
+        <div class="icon-title">fa-american-sign-language-interpreting</div>
+    </li>
+    <li><i class="fa fa-asl-interpreting"></i>
+        <div class="icon-title">fa-asl-interpreting</div>
+    </li>
+    <li><i class="fa fa-assistive-listening-systems"></i>
+        <div class="icon-title">fa-assistive-listening-systems</div>
+    </li>
+    <li><i class="fa fa-audio-description"></i>
+        <div class="icon-title">fa-audio-description</div>
+    </li>
+    <li><i class="fa fa-blind"></i>
+        <div class="icon-title">fa-blind</div>
+    </li>
+    <li><i class="fa fa-braille"></i>
+        <div class="icon-title">fa-braille</div>
+    </li>
+    <li><i class="fa fa-cc"></i>
+        <div class="icon-title">fa-cc</div>
+    </li>
+    <li><i class="fa fa-deaf"></i>
+        <div class="icon-title">fa-deaf</div>
+    </li>
+    <li><i class="fa fa-deafness"></i>
+        <div class="icon-title">fa-deafness</div>
+    </li>
+    <li><i class="fa fa-hard-of-hearing"></i>
+        <div class="icon-title">fa-hard-of-hearing</div>
+    </li>
+    <li><i class="fa fa-low-vision"></i>
+        <div class="icon-title">fa-low-vision</div>
+    </li>
+    <li><i class="fa fa-question-circle-o"></i>
+        <div class="icon-title">fa-question-circle-o</div>
+    </li>
+    <li><i class="fa fa-sign-language"></i>
+        <div class="icon-title">fa-sign-language</div>
+    </li>
+    <li><i class="fa fa-signing"></i>
+        <div class="icon-title">fa-signing</div>
+    </li>
+    <li><i class="fa fa-tty"></i>
+        <div class="icon-title">fa-tty</div>
+    </li>
+    <li><i class="fa fa-universal-access"></i>
+        <div class="icon-title">fa-universal-access</div>
+    </li>
+    <li><i class="fa fa-volume-control-phone"></i>
+        <div class="icon-title">fa-volume-control-phone</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-hand-grab-o"></i>
+        <div class="icon-title">fa-hand-grab-o</div>
+    </li>
+    <li><i class="fa fa-hand-lizard-o"></i>
+        <div class="icon-title">fa-hand-lizard-o</div>
+    </li>
+    <li><i class="fa fa-hand-o-down"></i>
+        <div class="icon-title">fa-hand-o-down</div>
+    </li>
+    <li><i class="fa fa-hand-o-left"></i>
+        <div class="icon-title">fa-hand-o-left</div>
+    </li>
+    <li><i class="fa fa-hand-o-right"></i>
+        <div class="icon-title">fa-hand-o-right</div>
+    </li>
+    <li><i class="fa fa-hand-o-up"></i>
+        <div class="icon-title">fa-hand-o-up</div>
+    </li>
+    <li><i class="fa fa-hand-paper-o"></i>
+        <div class="icon-title">fa-hand-paper-o</div>
+    </li>
+    <li><i class="fa fa-hand-peace-o"></i>
+        <div class="icon-title">fa-hand-peace-o</div>
+    </li>
+    <li><i class="fa fa-hand-pointer-o"></i>
+        <div class="icon-title">fa-hand-pointer-o</div>
+    </li>
+    <li><i class="fa fa-hand-rock-o"></i>
+        <div class="icon-title">fa-hand-rock-o</div>
+    </li>
+    <li><i class="fa fa-hand-scissors-o"></i>
+        <div class="icon-title">fa-hand-scissors-o</div>
+    </li>
+    <li><i class="fa fa-hand-spock-o"></i>
+        <div class="icon-title">fa-hand-spock-o</div>
+    </li>
+    <li><i class="fa fa-hand-stop-o"></i>
+        <div class="icon-title">fa-hand-stop-o</div>
+    </li>
+    <li><i class="fa fa-thumbs-down"></i>
+        <div class="icon-title">fa-thumbs-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-down"></i>
+        <div class="icon-title">fa-thumbs-o-down</div>
+    </li>
+    <li><i class="fa fa-thumbs-o-up"></i>
+        <div class="icon-title">fa-thumbs-o-up</div>
+    </li>
+    <li><i class="fa fa-thumbs-up"></i>
+        <div class="icon-title">fa-thumbs-up</div>
+    </li>
+    <li><i class="fa fa-ambulance"></i>
+        <div class="icon-title">fa-ambulance</div>
+    </li>
+    <li><i class="fa fa-automobile"></i>
+        <div class="icon-title">fa-automobile</div>
+    </li>
+    <li><i class="fa fa-bicycle"></i>
+        <div class="icon-title">fa-bicycle</div>
+    </li>
+    <li><i class="fa fa-bus"></i>
+        <div class="icon-title">fa-bus</div>
+    </li>
+    <li><i class="fa fa-cab"></i>
+        <div class="icon-title">fa-cab</div>
+    </li>
+    <li><i class="fa fa-car"></i>
+        <div class="icon-title">fa-car</div>
+    </li>
+    <li><i class="fa fa-fighter-jet"></i>
+        <div class="icon-title">fa-fighter-jet</div>
+    </li>
+    <li><i class="fa fa-motorcycle"></i>
+        <div class="icon-title">fa-motorcycle</div>
+    </li>
+    <li><i class="fa fa-plane"></i>
+        <div class="icon-title">fa-plane</div>
+    </li>
+    <li><i class="fa fa-rocket"></i>
+        <div class="icon-title">fa-rocket</div>
+    </li>
+    <li><i class="fa fa-ship"></i>
+        <div class="icon-title">fa-ship</div>
+    </li>
+    <li><i class="fa fa-space-shuttle"></i>
+        <div class="icon-title">fa-space-shuttle</div>
+    </li>
+    <li><i class="fa fa-subway"></i>
+        <div class="icon-title">fa-subway</div>
+    </li>
+    <li><i class="fa fa-taxi"></i>
+        <div class="icon-title">fa-taxi</div>
+    </li>
+    <li><i class="fa fa-train"></i>
+        <div class="icon-title">fa-train</div>
+    </li>
+    <li><i class="fa fa-truck"></i>
+        <div class="icon-title">fa-truck</div>
+    </li>
+    <li><i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li><i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+    <li><i class="fa fa-genderless"></i>
+        <div class="icon-title">fa-genderless</div>
+    </li>
+    <li><i class="fa fa-intersex"></i>
+        <div class="icon-title">fa-intersex</div>
+    </li>
+    <li><i class="fa fa-mars"></i>
+        <div class="icon-title">fa-mars</div>
+    </li>
+    <li><i class="fa fa-mars-double"></i>
+        <div class="icon-title">fa-mars-double</div>
+    </li>
+    <li><i class="fa fa-mars-stroke"></i>
+        <div class="icon-title">fa-mars-stroke</div>
+    </li>
+    <li><i class="fa fa-mars-stroke-h"></i>
+        <div class="icon-title">fa-mars-stroke-h</div>
+    </li>
+    <li><i class="fa fa-mars-stroke-v"></i>
+        <div class="icon-title">fa-mars-stroke-v</div>
+    </li>
+    <li><i class="fa fa-mercury"></i>
+        <div class="icon-title">fa-mercury</div>
+    </li>
+    <li><i class="fa fa-neuter"></i>
+        <div class="icon-title">fa-neuter</div>
+    </li>
+    <li><i class="fa fa-transgender"></i>
+        <div class="icon-title">fa-transgender</div>
+    </li>
+    <li><i class="fa fa-transgender-alt"></i>
+        <div class="icon-title">fa-transgender-alt</div>
+    </li>
+    <li><i class="fa fa-venus"></i>
+        <div class="icon-title">fa-venus</div>
+    </li>
+    <li><i class="fa fa-venus-double"></i>
+        <div class="icon-title">fa-venus-double</div>
+    </li>
+    <li><i class="fa fa-venus-mars"></i>
+        <div class="icon-title">fa-venus-mars</div>
+    </li>
+    <li><i class="fa fa-file"></i>
+        <div class="icon-title">fa-file</div>
+    </li>
+    <li><i class="fa fa-file-archive-o"></i>
+        <div class="icon-title">fa-file-archive-o</div>
+    </li>
+    <li><i class="fa fa-file-audio-o"></i>
+        <div class="icon-title">fa-file-audio-o</div>
+    </li>
+    <li><i class="fa fa-file-code-o"></i>
+        <div class="icon-title">fa-file-code-o</div>
+    </li>
+    <li><i class="fa fa-file-excel-o"></i>
+        <div class="icon-title">fa-file-excel-o</div>
+    </li>
+    <li><i class="fa fa-file-image-o"></i>
+        <div class="icon-title">fa-file-image-o</div>
+    </li>
+    <li><i class="fa fa-file-movie-o"></i>
+        <div class="icon-title">fa-file-movie-o</div>
+    </li>
+    <li><i class="fa fa-file-o"></i>
+        <div class="icon-title">fa-file-o</div>
+    </li>
+    <li><i class="fa fa-file-pdf-o"></i>
+        <div class="icon-title">fa-file-pdf-o</div>
+    </li>
+    <li><i class="fa fa-file-photo-o"></i>
+        <div class="icon-title">fa-file-photo-o</div>
+    </li>
+    <li><i class="fa fa-file-picture-o"></i>
+        <div class="icon-title">fa-file-picture-o</div>
+    </li>
+    <li><i class="fa fa-file-powerpoint-o"></i>
+        <div class="icon-title">fa-file-powerpoint-o</div>
+    </li>
+    <li><i class="fa fa-file-sound-o"></i>
+        <div class="icon-title">fa-file-sound-o</div>
+    </li>
+    <li><i class="fa fa-file-text"></i>
+        <div class="icon-title">fa-file-text</div>
+    </li>
+    <li><i class="fa fa-file-text-o"></i>
+        <div class="icon-title">fa-file-text-o</div>
+    </li>
+    <li><i class="fa fa-file-video-o"></i>
+        <div class="icon-title">fa-file-video-o</div>
+    </li>
+    <li><i class="fa fa-file-word-o"></i>
+        <div class="icon-title">fa-file-word-o</div>
+    </li>
+    <li><i class="fa fa-file-zip-o"></i>
+        <div class="icon-title">fa-file-zip-o</div>
+    </li>
+    <li><i class="fa fa-circle-o-notch"></i>
+        <div class="icon-title">fa-circle-o-notch</div>
+    </li>
+    <li><i class="fa fa-cog"></i>
+        <div class="icon-title">fa-cog</div>
+    </li>
+    <li><i class="fa fa-gear"></i>
+        <div class="icon-title">fa-gear</div>
+    </li>
+    <li><i class="fa fa-refresh"></i>
+        <div class="icon-title">fa-refresh</div>
+    </li>
+    <li><i class="fa fa-spinner"></i>
+        <div class="icon-title">fa-spinner</div>
+    </li>
+    <li><i class="fa fa-check-square"></i>
+        <div class="icon-title">fa-check-square</div>
+    </li>
+    <li><i class="fa fa-check-square-o"></i>
+        <div class="icon-title">fa-check-square-o</div>
+    </li>
+    <li><i class="fa fa-circle"></i>
+        <div class="icon-title">fa-circle</div>
+    </li>
+    <li><i class="fa fa-circle-o"></i>
+        <div class="icon-title">fa-circle-o</div>
+    </li>
+    <li><i class="fa fa-dot-circle-o"></i>
+        <div class="icon-title">fa-dot-circle-o</div>
+    </li>
+    <li><i class="fa fa-minus-square"></i>
+        <div class="icon-title">fa-minus-square</div>
+    </li>
+    <li><i class="fa fa-minus-square-o"></i>
+        <div class="icon-title">fa-minus-square-o</div>
+    </li>
+    <li><i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li><i class="fa fa-plus-square-o"></i>
+        <div class="icon-title">fa-plus-square-o</div>
+    </li>
+    <li><i class="fa fa-square"></i>
+        <div class="icon-title">fa-square</div>
+    </li>
+    <li><i class="fa fa-square-o"></i>
+        <div class="icon-title">fa-square-o</div>
+    </li>
+    <li><i class="fa fa-cc-amex"></i>
+        <div class="icon-title">fa-cc-amex</div>
+    </li>
+    <li><i class="fa fa-cc-diners-club"></i>
+        <div class="icon-title">fa-cc-diners-club</div>
+    </li>
+    <li><i class="fa fa-cc-discover"></i>
+        <div class="icon-title">fa-cc-discover</div>
+    </li>
+    <li><i class="fa fa-cc-jcb"></i>
+        <div class="icon-title">fa-cc-jcb</div>
+    </li>
+    <li><i class="fa fa-cc-mastercard"></i>
+        <div class="icon-title">fa-cc-mastercard</div>
+    </li>
+    <li><i class="fa fa-cc-paypal"></i>
+        <div class="icon-title">fa-cc-paypal</div>
+    </li>
+    <li><i class="fa fa-cc-stripe"></i>
+        <div class="icon-title">fa-cc-stripe</div>
+    </li>
+    <li><i class="fa fa-cc-visa"></i>
+        <div class="icon-title">fa-cc-visa</div>
+    </li>
+    <li><i class="fa fa-credit-card"></i>
+        <div class="icon-title">fa-credit-card</div>
+    </li>
+    <li><i class="fa fa-credit-card-alt"></i>
+        <div class="icon-title">fa-credit-card-alt</div>
+    </li>
+    <li><i class="fa fa-google-wallet"></i>
+        <div class="icon-title">fa-google-wallet</div>
+    </li>
+    <li><i class="fa fa-paypal"></i>
+        <div class="icon-title">fa-paypal</div>
+    </li>
+    <li><i class="fa fa-area-chart"></i>
+        <div class="icon-title">fa-area-chart</div>
+    </li>
+    <li><i class="fa fa-bar-chart"></i>
+        <div class="icon-title">fa-bar-chart</div>
+    </li>
+    <li><i class="fa fa-bar-chart-o"></i>
+        <div class="icon-title">fa-bar-chart-o</div>
+    </li>
+    <li><i class="fa fa-line-chart"></i>
+        <div class="icon-title">fa-line-chart</div>
+    </li>
+    <li><i class="fa fa-pie-chart"></i>
+        <div class="icon-title">fa-pie-chart</div>
+    </li>
+    <li><i class="fa fa-bitcoin"></i>
+        <div class="icon-title">fa-bitcoin</div>
+    </li>
+    <li><i class="fa fa-btc"></i>
+        <div class="icon-title">fa-btc</div>
+    </li>
+    <li><i class="fa fa-cny"></i>
+        <div class="icon-title">fa-cny</div>
+    </li>
+    <li><i class="fa fa-dollar"></i>
+        <div class="icon-title">fa-dollar</div>
+    </li>
+    <li><i class="fa fa-eur"></i>
+        <div class="icon-title">fa-eur</div>
+    </li>
+    <li><i class="fa fa-euro"></i>
+        <div class="icon-title">fa-euro</div>
+    </li>
+    <li><i class="fa fa-gbp"></i>
+        <div class="icon-title">fa-gbp</div>
+    </li>
+    <li><i class="fa fa-gg"></i>
+        <div class="icon-title">fa-gg</div>
+    </li>
+    <li><i class="fa fa-gg-circle"></i>
+        <div class="icon-title">fa-gg-circle</div>
+    </li>
+    <li><i class="fa fa-ils"></i>
+        <div class="icon-title">fa-ils</div>
+    </li>
+    <li><i class="fa fa-inr"></i>
+        <div class="icon-title">fa-inr</div>
+    </li>
+    <li><i class="fa fa-jpy"></i>
+        <div class="icon-title">fa-jpy</div>
+    </li>
+    <li><i class="fa fa-krw"></i>
+        <div class="icon-title">fa-krw</div>
+    </li>
+    <li><i class="fa fa-money"></i>
+        <div class="icon-title">fa-money</div>
+    </li>
+    <li><i class="fa fa-rmb"></i>
+        <div class="icon-title">fa-rmb</div>
+    </li>
+    <li><i class="fa fa-rouble"></i>
+        <div class="icon-title">fa-rouble</div>
+    </li>
+    <li><i class="fa fa-rub"></i>
+        <div class="icon-title">fa-rub</div>
+    </li>
+    <li><i class="fa fa-ruble"></i>
+        <div class="icon-title">fa-ruble</div>
+    </li>
+    <li><i class="fa fa-rupee"></i>
+        <div class="icon-title">fa-rupee</div>
+    </li>
+    <li><i class="fa fa-shekel"></i>
+        <div class="icon-title">fa-shekel</div>
+    </li>
+    <li><i class="fa fa-sheqel"></i>
+        <div class="icon-title">fa-sheqel</div>
+    </li>
+    <li><i class="fa fa-try"></i>
+        <div class="icon-title">fa-try</div>
+    </li>
+    <li><i class="fa fa-turkish-lira"></i>
+        <div class="icon-title">fa-turkish-lira</div>
+    </li>
+    <li><i class="fa fa-usd"></i>
+        <div class="icon-title">fa-usd</div>
+    </li>
+    <li><i class="fa fa-won"></i>
+        <div class="icon-title">fa-won</div>
+    </li>
+    <li><i class="fa fa-yen"></i>
+        <div class="icon-title">fa-yen</div>
+    </li>
+    <li><i class="fa fa-align-center"></i>
+        <div class="icon-title">fa-align-center</div>
+    </li>
+    <li><i class="fa fa-align-justify"></i>
+        <div class="icon-title">fa-align-justify</div>
+    </li>
+    <li><i class="fa fa-align-left"></i>
+        <div class="icon-title">fa-align-left</div>
+    </li>
+    <li><i class="fa fa-align-right"></i>
+        <div class="icon-title">fa-align-right</div>
+    </li>
+    <li><i class="fa fa-bold"></i>
+        <div class="icon-title">fa-bold</div>
+    </li>
+    <li><i class="fa fa-chain"></i>
+        <div class="icon-title">fa-chain</div>
+    </li>
+    <li><i class="fa fa-chain-broken"></i>
+        <div class="icon-title">fa-chain-broken</div>
+    </li>
+    <li><i class="fa fa-clipboard"></i>
+        <div class="icon-title">fa-clipboard</div>
+    </li>
+    <li><i class="fa fa-columns"></i>
+        <div class="icon-title">fa-columns</div>
+    </li>
+    <li><i class="fa fa-copy"></i>
+        <div class="icon-title">fa-copy</div>
+    </li>
+    <li><i class="fa fa-cut"></i>
+        <div class="icon-title">fa-cut</div>
+    </li>
+    <li><i class="fa fa-dedent"></i>
+        <div class="icon-title">fa-dedent</div>
+    </li>
+    <li><i class="fa fa-eraser"></i>
+        <div class="icon-title">fa-eraser</div>
+    </li>
+    <li><i class="fa fa-file"></i>
+        <div class="icon-title">fa-file</div>
+    </li>
+    <li><i class="fa fa-file-o"></i>
+        <div class="icon-title">fa-file-o</div>
+    </li>
+    <li><i class="fa fa-file-text"></i>
+        <div class="icon-title">fa-file-text</div>
+    </li>
+    <li><i class="fa fa-file-text-o"></i>
+        <div class="icon-title">fa-file-text-o</div>
+    </li>
+    <li><i class="fa fa-files-o"></i>
+        <div class="icon-title">fa-files-o</div>
+    </li>
+    <li><i class="fa fa-floppy-o"></i>
+        <div class="icon-title">fa-floppy-o</div>
+    </li>
+    <li><i class="fa fa-font"></i>
+        <div class="icon-title">fa-font</div>
+    </li>
+    <li><i class="fa fa-header"></i>
+        <div class="icon-title">fa-header</div>
+    </li>
+    <li><i class="fa fa-indent"></i>
+        <div class="icon-title">fa-indent</div>
+    </li>
+    <li><i class="fa fa-italic"></i>
+        <div class="icon-title">fa-italic</div>
+    </li>
+    <li><i class="fa fa-link"></i>
+        <div class="icon-title">fa-link</div>
+    </li>
+    <li><i class="fa fa-list"></i>
+        <div class="icon-title">fa-list</div>
+    </li>
+    <li><i class="fa fa-list-alt"></i>
+        <div class="icon-title">fa-list-alt</div>
+    </li>
+    <li><i class="fa fa-list-ol"></i>
+        <div class="icon-title">fa-list-ol</div>
+    </li>
+    <li><i class="fa fa-list-ul"></i>
+        <div class="icon-title">fa-list-ul</div>
+    </li>
+    <li><i class="fa fa-outdent"></i>
+        <div class="icon-title">fa-outdent</div>
+    </li>
+    <li><i class="fa fa-paperclip"></i>
+        <div class="icon-title">fa-paperclip</div>
+    </li>
+    <li><i class="fa fa-paragraph"></i>
+        <div class="icon-title">fa-paragraph</div>
+    </li>
+    <li><i class="fa fa-paste"></i>
+        <div class="icon-title">fa-paste</div>
+    </li>
+    <li><i class="fa fa-repeat"></i>
+        <div class="icon-title">fa-repeat</div>
+    </li>
+    <li><i class="fa fa-rotate-left"></i>
+        <div class="icon-title">fa-rotate-left</div>
+    </li>
+    <li><i class="fa fa-rotate-right"></i>
+        <div class="icon-title">fa-rotate-right</div>
+    </li>
+    <li><i class="fa fa-save"></i>
+        <div class="icon-title">fa-save</div>
+    </li>
+    <li><i class="fa fa-scissors"></i>
+        <div class="icon-title">fa-scissors</div>
+    </li>
+    <li><i class="fa fa-strikethrough"></i>
+        <div class="icon-title">fa-strikethrough</div>
+    </li>
+    <li><i class="fa fa-subscript"></i>
+        <div class="icon-title">fa-subscript</div>
+    </li>
+    <li><i class="fa fa-superscript"></i>
+        <div class="icon-title">fa-superscript</div>
+    </li>
+    <li><i class="fa fa-table"></i>
+        <div class="icon-title">fa-table</div>
+    </li>
+    <li><i class="fa fa-text-height"></i>
+        <div class="icon-title">fa-text-height</div>
+    </li>
+    <li><i class="fa fa-text-width"></i>
+        <div class="icon-title">fa-text-width</div>
+    </li>
+    <li><i class="fa fa-th"></i>
+        <div class="icon-title">fa-th</div>
+    </li>
+    <li><i class="fa fa-th-large"></i>
+        <div class="icon-title">fa-th-large</div>
+    </li>
+    <li><i class="fa fa-th-list"></i>
+        <div class="icon-title">fa-th-list</div>
+    </li>
+    <li><i class="fa fa-underline"></i>
+        <div class="icon-title">fa-underline</div>
+    </li>
+    <li><i class="fa fa-undo"></i>
+        <div class="icon-title">fa-undo</div>
+    </li>
+    <li><i class="fa fa-unlink"></i>
+        <div class="icon-title">fa-unlink</div>
+    </li>
+    <li><i class="fa fa-angle-double-down"></i>
+        <div class="icon-title">fa-angle-double-down</div>
+    </li>
+    <li><i class="fa fa-angle-double-left"></i>
+        <div class="icon-title">fa-angle-double-left</div>
+    </li>
+    <li><i class="fa fa-angle-double-right"></i>
+        <div class="icon-title">fa-angle-double-right</div>
+    </li>
+    <li><i class="fa fa-angle-double-up"></i>
+        <div class="icon-title">fa-angle-double-up</div>
+    </li>
+    <li><i class="fa fa-angle-down"></i>
+        <div class="icon-title">fa-angle-down</div>
+    </li>
+    <li><i class="fa fa-angle-left"></i>
+        <div class="icon-title">fa-angle-left</div>
+    </li>
+    <li><i class="fa fa-angle-right"></i>
+        <div class="icon-title">fa-angle-right</div>
+    </li>
+    <li><i class="fa fa-angle-up"></i>
+        <div class="icon-title">fa-angle-up</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-down"></i>
+        <div class="icon-title">fa-arrow-circle-down</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-left"></i>
+        <div class="icon-title">fa-arrow-circle-left</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-down"></i>
+        <div class="icon-title">fa-arrow-circle-o-down</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-left"></i>
+        <div class="icon-title">fa-arrow-circle-o-left</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-right"></i>
+        <div class="icon-title">fa-arrow-circle-o-right</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-o-up"></i>
+        <div class="icon-title">fa-arrow-circle-o-up</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-right"></i>
+        <div class="icon-title">fa-arrow-circle-right</div>
+    </li>
+    <li><i class="fa fa-arrow-circle-up"></i>
+        <div class="icon-title">fa-arrow-circle-up</div>
+    </li>
+    <li><i class="fa fa-arrow-down"></i>
+        <div class="icon-title">fa-arrow-down</div>
+    </li>
+    <li><i class="fa fa-arrow-left"></i>
+        <div class="icon-title">fa-arrow-left</div>
+    </li>
+    <li><i class="fa fa-arrow-right"></i>
+        <div class="icon-title">fa-arrow-right</div>
+    </li>
+    <li><i class="fa fa-arrow-up"></i>
+        <div class="icon-title">fa-arrow-up</div>
+    </li>
+    <li><i class="fa fa-arrows"></i>
+        <div class="icon-title">fa-arrows</div>
+    </li>
+    <li><i class="fa fa-arrows-alt"></i>
+        <div class="icon-title">fa-arrows-alt</div>
+    </li>
+    <li><i class="fa fa-arrows-h"></i>
+        <div class="icon-title">fa-arrows-h</div>
+    </li>
+    <li><i class="fa fa-arrows-v"></i>
+        <div class="icon-title">fa-arrows-v</div>
+    </li>
+    <li><i class="fa fa-caret-down"></i>
+        <div class="icon-title">fa-caret-down</div>
+    </li>
+    <li><i class="fa fa-caret-left"></i>
+        <div class="icon-title">fa-caret-left</div>
+    </li>
+    <li><i class="fa fa-caret-right"></i>
+        <div class="icon-title">fa-caret-right</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-down"></i>
+        <div class="icon-title">fa-caret-square-o-down</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-left"></i>
+        <div class="icon-title">fa-caret-square-o-left</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-right"></i>
+        <div class="icon-title">fa-caret-square-o-right</div>
+    </li>
+    <li><i class="fa fa-caret-square-o-up"></i>
+        <div class="icon-title">fa-caret-square-o-up</div>
+    </li>
+    <li><i class="fa fa-caret-up"></i>
+        <div class="icon-title">fa-caret-up</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-down"></i>
+        <div class="icon-title">fa-chevron-circle-down</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-left"></i>
+        <div class="icon-title">fa-chevron-circle-left</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-right"></i>
+        <div class="icon-title">fa-chevron-circle-right</div>
+    </li>
+    <li><i class="fa fa-chevron-circle-up"></i>
+        <div class="icon-title">fa-chevron-circle-up</div>
+    </li>
+    <li><i class="fa fa-chevron-down"></i>
+        <div class="icon-title">fa-chevron-down</div>
+    </li>
+    <li><i class="fa fa-chevron-left"></i>
+        <div class="icon-title">fa-chevron-left</div>
+    </li>
+    <li><i class="fa fa-chevron-right"></i>
+        <div class="icon-title">fa-chevron-right</div>
+    </li>
+    <li><i class="fa fa-chevron-up"></i>
+        <div class="icon-title">fa-chevron-up</div>
+    </li>
+    <li><i class="fa fa-exchange"></i>
+        <div class="icon-title">fa-exchange</div>
+    </li>
+    <li><i class="fa fa-hand-o-down"></i>
+        <div class="icon-title">fa-hand-o-down</div>
+    </li>
+    <li><i class="fa fa-hand-o-left"></i>
+        <div class="icon-title">fa-hand-o-left</div>
+    </li>
+    <li><i class="fa fa-hand-o-right"></i>
+        <div class="icon-title">fa-hand-o-right</div>
+    </li>
+    <li><i class="fa fa-hand-o-up"></i>
+        <div class="icon-title">fa-hand-o-up</div>
+    </li>
+    <li><i class="fa fa-long-arrow-down"></i>
+        <div class="icon-title">fa-long-arrow-down</div>
+    </li>
+    <li><i class="fa fa-long-arrow-left"></i>
+        <div class="icon-title">fa-long-arrow-left</div>
+    </li>
+    <li><i class="fa fa-long-arrow-right"></i>
+        <div class="icon-title">fa-long-arrow-right</div>
+    </li>
+    <li><i class="fa fa-long-arrow-up"></i>
+        <div class="icon-title">fa-long-arrow-up</div>
+    </li>
+    <li><i class="fa fa-toggle-down"></i>
+        <div class="icon-title">fa-toggle-down</div>
+    </li>
+    <li><i class="fa fa-toggle-left"></i>
+        <div class="icon-title">fa-toggle-left</div>
+    </li>
+    <li><i class="fa fa-toggle-right"></i>
+        <div class="icon-title">fa-toggle-right</div>
+    </li>
+    <li><i class="fa fa-toggle-up"></i>
+        <div class="icon-title">fa-toggle-up</div>
+    </li>
+    <li><i class="fa fa-arrows-alt"></i>
+        <div class="icon-title">fa-arrows-alt</div>
+    </li>
+    <li><i class="fa fa-backward"></i>
+        <div class="icon-title">fa-backward</div>
+    </li>
+    <li><i class="fa fa-compress"></i>
+        <div class="icon-title">fa-compress</div>
+    </li>
+    <li><i class="fa fa-eject"></i>
+        <div class="icon-title">fa-eject</div>
+    </li>
+    <li><i class="fa fa-expand"></i>
+        <div class="icon-title">fa-expand</div>
+    </li>
+    <li><i class="fa fa-fast-backward"></i>
+        <div class="icon-title">fa-fast-backward</div>
+    </li>
+    <li><i class="fa fa-fast-forward"></i>
+        <div class="icon-title">fa-fast-forward</div>
+    </li>
+    <li><i class="fa fa-forward"></i>
+        <div class="icon-title">fa-forward</div>
+    </li>
+    <li><i class="fa fa-pause"></i>
+        <div class="icon-title">fa-pause</div>
+    </li>
+    <li><i class="fa fa-pause-circle"></i>
+        <div class="icon-title">fa-pause-circle</div>
+    </li>
+    <li><i class="fa fa-pause-circle-o"></i>
+        <div class="icon-title">fa-pause-circle-o</div>
+    </li>
+    <li><i class="fa fa-play"></i>
+        <div class="icon-title">fa-play</div>
+    </li>
+    <li><i class="fa fa-play-circle"></i>
+        <div class="icon-title">fa-play-circle</div>
+    </li>
+    <li><i class="fa fa-play-circle-o"></i>
+        <div class="icon-title">fa-play-circle-o</div>
+    </li>
+    <li><i class="fa fa-random"></i>
+        <div class="icon-title">fa-random</div>
+    </li>
+    <li><i class="fa fa-step-backward"></i>
+        <div class="icon-title">fa-step-backward</div>
+    </li>
+    <li><i class="fa fa-step-forward"></i>
+        <div class="icon-title">fa-step-forward</div>
+    </li>
+    <li><i class="fa fa-stop"></i>
+        <div class="icon-title">fa-stop</div>
+    </li>
+    <li><i class="fa fa-stop-circle"></i>
+        <div class="icon-title">fa-stop-circle</div>
+    </li>
+    <li><i class="fa fa-stop-circle-o"></i>
+        <div class="icon-title">fa-stop-circle-o</div>
+    </li>
+    <li><i class="fa fa-youtube-play"></i>
+        <div class="icon-title">fa-youtube-play</div>
+    </li>
+    <li><i class="fa fa-500px"></i>
+        <div class="icon-title">fa-500px</div>
+    </li>
+    <li><i class="fa fa-adn"></i>
+        <div class="icon-title">fa-adn</div>
+    </li>
+    <li><i class="fa fa-amazon"></i>
+        <div class="icon-title">fa-amazon</div>
+    </li>
+    <li><i class="fa fa-android"></i>
+        <div class="icon-title">fa-android</div>
+    </li>
+    <li><i class="fa fa-angellist"></i>
+        <div class="icon-title">fa-angellist</div>
+    </li>
+    <li><i class="fa fa-apple"></i>
+        <div class="icon-title">fa-apple</div>
+    </li>
+    <li><i class="fa fa-bandcamp"></i>
+        <div class="icon-title">fa-bandcamp</div>
+    </li>
+    <li><i class="fa fa-behance"></i>
+        <div class="icon-title">fa-behance</div>
+    </li>
+    <li><i class="fa fa-behance-square"></i>
+        <div class="icon-title">fa-behance-square</div>
+    </li>
+    <li><i class="fa fa-bitbucket"></i>
+        <div class="icon-title">fa-bitbucket</div>
+    </li>
+    <li><i class="fa fa-bitbucket-square"></i>
+        <div class="icon-title">fa-bitbucket-square</div>
+    </li>
+    <li><i class="fa fa-bitcoin"></i>
+        <div class="icon-title">fa-bitcoin</div>
+    </li>
+    <li><i class="fa fa-black-tie"></i>
+        <div class="icon-title">fa-black-tie</div>
+    </li>
+    <li><i class="fa fa-bluetooth"></i>
+        <div class="icon-title">fa-bluetooth</div>
+    </li>
+    <li><i class="fa fa-bluetooth-b"></i>
+        <div class="icon-title">fa-bluetooth-b</div>
+    </li>
+    <li><i class="fa fa-btc"></i>
+        <div class="icon-title">fa-btc</div>
+    </li>
+    <li><i class="fa fa-buysellads"></i>
+        <div class="icon-title">fa-buysellads</div>
+    </li>
+    <li><i class="fa fa-cc-amex"></i>
+        <div class="icon-title">fa-cc-amex</div>
+    </li>
+    <li><i class="fa fa-cc-diners-club"></i>
+        <div class="icon-title">fa-cc-diners-club</div>
+    </li>
+    <li><i class="fa fa-cc-discover"></i>
+        <div class="icon-title">fa-cc-discover</div>
+    </li>
+    <li><i class="fa fa-cc-jcb"></i>
+        <div class="icon-title">fa-cc-jcb</div>
+    </li>
+    <li><i class="fa fa-cc-mastercard"></i>
+        <div class="icon-title">fa-cc-mastercard</div>
+    </li>
+    <li><i class="fa fa-cc-paypal"></i>
+        <div class="icon-title">fa-cc-paypal</div>
+    </li>
+    <li><i class="fa fa-cc-stripe"></i>
+        <div class="icon-title">fa-cc-stripe</div>
+    </li>
+    <li><i class="fa fa-cc-visa"></i>
+        <div class="icon-title">fa-cc-visa</div>
+    </li>
+    <li><i class="fa fa-chrome"></i>
+        <div class="icon-title">fa-chrome</div>
+    </li>
+    <li><i class="fa fa-codepen"></i>
+        <div class="icon-title">fa-codepen</div>
+    </li>
+    <li><i class="fa fa-codiepie"></i>
+        <div class="icon-title">fa-codiepie</div>
+    </li>
+    <li><i class="fa fa-connectdevelop"></i>
+        <div class="icon-title">fa-connectdevelop</div>
+    </li>
+    <li><i class="fa fa-contao"></i>
+        <div class="icon-title">fa-contao</div>
+    </li>
+    <li><i class="fa fa-css3"></i>
+        <div class="icon-title">fa-css3</div>
+    </li>
+    <li><i class="fa fa-dashcube"></i>
+        <div class="icon-title">fa-dashcube</div>
+    </li>
+    <li><i class="fa fa-delicious"></i>
+        <div class="icon-title">fa-delicious</div>
+    </li>
+    <li><i class="fa fa-deviantart"></i>
+        <div class="icon-title">fa-deviantart</div>
+    </li>
+    <li><i class="fa fa-digg"></i>
+        <div class="icon-title">fa-digg</div>
+    </li>
+    <li><i class="fa fa-dribbble"></i>
+        <div class="icon-title">fa-dribbble</div>
+    </li>
+    <li><i class="fa fa-dropbox"></i>
+        <div class="icon-title">fa-dropbox</div>
+    </li>
+    <li><i class="fa fa-drupal"></i>
+        <div class="icon-title">fa-drupal</div>
+    </li>
+    <li><i class="fa fa-edge"></i>
+        <div class="icon-title">fa-edge</div>
+    </li>
+    <li><i class="fa fa-eercast"></i>
+        <div class="icon-title">fa-eercast</div>
+    </li>
+    <li><i class="fa fa-empire"></i>
+        <div class="icon-title">fa-empire</div>
+    </li>
+    <li><i class="fa fa-envira"></i>
+        <div class="icon-title">fa-envira</div>
+    </li>
+    <li><i class="fa fa-etsy"></i>
+        <div class="icon-title">fa-etsy</div>
+    </li>
+    <li><i class="fa fa-expeditedssl"></i>
+        <div class="icon-title">fa-expeditedssl</div>
+    </li>
+    <li><i class="fa fa-fa"></i>
+        <div class="icon-title">fa-fa</div>
+    </li>
+    <li><i class="fa fa-facebook"></i>
+        <div class="icon-title">fa-facebook</div>
+    </li>
+    <li><i class="fa fa-facebook-f"></i>
+        <div class="icon-title">fa-facebook-f</div>
+    </li>
+    <li><i class="fa fa-facebook-official"></i>
+        <div class="icon-title">fa-facebook-official</div>
+    </li>
+    <li><i class="fa fa-facebook-square"></i>
+        <div class="icon-title">fa-facebook-square</div>
+    </li>
+    <li><i class="fa fa-firefox"></i>
+        <div class="icon-title">fa-firefox</div>
+    </li>
+    <li><i class="fa fa-first-order"></i>
+        <div class="icon-title">fa-first-order</div>
+    </li>
+    <li><i class="fa fa-flickr"></i>
+        <div class="icon-title">fa-flickr</div>
+    </li>
+    <li><i class="fa fa-font-awesome"></i>
+        <div class="icon-title">fa-font-awesome</div>
+    </li>
+    <li><i class="fa fa-fonticons"></i>
+        <div class="icon-title">fa-fonticons</div>
+    </li>
+    <li><i class="fa fa-fort-awesome"></i>
+        <div class="icon-title">fa-fort-awesome</div>
+    </li>
+    <li><i class="fa fa-forumbee"></i>
+        <div class="icon-title">fa-forumbee</div>
+    </li>
+    <li><i class="fa fa-foursquare"></i>
+        <div class="icon-title">fa-foursquare</div>
+    </li>
+    <li><i class="fa fa-free-code-camp"></i>
+        <div class="icon-title">fa-free-code-camp</div>
+    </li>
+    <li><i class="fa fa-ge"></i>
+        <div class="icon-title">fa-ge</div>
+    </li>
+    <li><i class="fa fa-get-pocket"></i>
+        <div class="icon-title">fa-get-pocket</div>
+    </li>
+    <li><i class="fa fa-gg"></i>
+        <div class="icon-title">fa-gg</div>
+    </li>
+    <li><i class="fa fa-gg-circle"></i>
+        <div class="icon-title">fa-gg-circle</div>
+    </li>
+    <li><i class="fa fa-git"></i>
+        <div class="icon-title">fa-git</div>
+    </li>
+    <li><i class="fa fa-git-square"></i>
+        <div class="icon-title">fa-git-square</div>
+    </li>
+    <li><i class="fa fa-github"></i>
+        <div class="icon-title">fa-github</div>
+    </li>
+    <li><i class="fa fa-github-alt"></i>
+        <div class="icon-title">fa-github-alt</div>
+    </li>
+    <li><i class="fa fa-github-square"></i>
+        <div class="icon-title">fa-github-square</div>
+    </li>
+    <li><i class="fa fa-gitlab"></i>
+        <div class="icon-title">fa-gitlab</div>
+    </li>
+    <li><i class="fa fa-gittip"></i>
+        <div class="icon-title">fa-gittip</div>
+    </li>
+    <li><i class="fa fa-glide"></i>
+        <div class="icon-title">fa-glide</div>
+    </li>
+    <li><i class="fa fa-glide-g"></i>
+        <div class="icon-title">fa-glide-g</div>
+    </li>
+    <li><i class="fa fa-google"></i>
+        <div class="icon-title">fa-google</div>
+    </li>
+    <li><i class="fa fa-google-plus"></i>
+        <div class="icon-title">fa-google-plus</div>
+    </li>
+    <li><i class="fa fa-google-plus-circle"></i>
+        <div class="icon-title">fa-google-plus-circle</div>
+    </li>
+    <li><i class="fa fa-google-plus-official"></i>
+        <div class="icon-title">fa-google-plus-official</div>
+    </li>
+    <li><i class="fa fa-google-plus-square"></i>
+        <div class="icon-title">fa-google-plus-square</div>
+    </li>
+    <li><i class="fa fa-google-wallet"></i>
+        <div class="icon-title">fa-google-wallet</div>
+    </li>
+    <li><i class="fa fa-gratipay"></i>
+        <div class="icon-title">fa-gratipay</div>
+    </li>
+    <li><i class="fa fa-grav"></i>
+        <div class="icon-title">fa-grav</div>
+    </li>
+    <li><i class="fa fa-hacker-news"></i>
+        <div class="icon-title">fa-hacker-news</div>
+    </li>
+    <li><i class="fa fa-houzz"></i>
+        <div class="icon-title">fa-houzz</div>
+    </li>
+    <li><i class="fa fa-html5"></i>
+        <div class="icon-title">fa-html5</div>
+    </li>
+    <li><i class="fa fa-imdb"></i>
+        <div class="icon-title">fa-imdb</div>
+    </li>
+    <li><i class="fa fa-instagram"></i>
+        <div class="icon-title">fa-instagram</div>
+    </li>
+    <li><i class="fa fa-internet-explorer"></i>
+        <div class="icon-title">fa-internet-explorer</div>
+    </li>
+    <li><i class="fa fa-ioxhost"></i>
+        <div class="icon-title">fa-ioxhost</div>
+    </li>
+    <li><i class="fa fa-joomla"></i>
+        <div class="icon-title">fa-joomla</div>
+    </li>
+    <li><i class="fa fa-jsfiddle"></i>
+        <div class="icon-title">fa-jsfiddle</div>
+    </li>
+    <li><i class="fa fa-lastfm"></i>
+        <div class="icon-title">fa-lastfm</div>
+    </li>
+    <li><i class="fa fa-lastfm-square"></i>
+        <div class="icon-title">fa-lastfm-square</div>
+    </li>
+    <li><i class="fa fa-leanpub"></i>
+        <div class="icon-title">fa-leanpub</div>
+    </li>
+    <li><i class="fa fa-linkedin"></i>
+        <div class="icon-title">fa-linkedin</div>
+    </li>
+    <li>
+        <i class="fa fa-linkedin-square"></i>
+        <div class="icon-title">fa-linkedin-square</div>
+    </li>
+    <li>
+        <i class="fa fa-linode"></i>
+        <div class="icon-title">fa-linode</div>
+    </li>
+    <li>
+        <i class="fa fa-linux"></i>
+        <div class="icon-title">fa-linux</div>
+    </li>
+    <li>
+        <i class="fa fa-maxcdn"></i>
+        <div class="icon-title">fa-maxcdn</div>
+    </li>
+    <li>
+        <i class="fa fa-meanpath"></i>
+        <div class="icon-title">fa-meanpath</div>
+    </li>
+    <li>
+        <i class="fa fa-medium"></i>
+        <div class="icon-title">fa-medium</div>
+    </li>
+    <li>
+        <i class="fa fa-meetup"></i>
+        <div class="icon-title">fa-meetup</div>
+    </li>
+    <li>
+        <i class="fa fa-mixcloud"></i>
+        <div class="icon-title">fa-mixcloud</div>
+    </li>
+    <li>
+        <i class="fa fa-modx"></i>
+        <div class="icon-title">fa-modx</div>
+    </li>
+    <li>
+        <i class="fa fa-odnoklassniki"></i>
+        <div class="icon-title">fa-odnoklassniki</div>
+    </li>
+    <li>
+        <i class="fa fa-odnoklassniki-square"></i>
+        <div class="icon-title">fa-odnoklassniki-square</div>
+    </li>
+    <li>
+        <i class="fa fa-opencart"></i>
+        <div class="icon-title">fa-opencart</div>
+    </li>
+    <li>
+        <i class="fa fa-openid"></i>
+        <div class="icon-title">fa-openid</div>
+    </li>
+    <li>
+        <i class="fa fa-opera"></i>
+        <div class="icon-title">fa-opera</div>
+    </li>
+    <li>
+        <i class="fa fa-optin-monster"></i>
+        <div class="icon-title">fa-optin-monster</div>
+    </li>
+    <li>
+        <i class="fa fa-pagelines"></i>
+        <div class="icon-title">fa-pagelines</div>
+    </li>
+    <li>
+        <i class="fa fa-paypal"></i>
+        <div class="icon-title">fa-paypal</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper"></i>
+        <div class="icon-title">fa-pied-piper</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper-alt"></i>
+        <div class="icon-title">fa-pied-piper-alt</div>
+    </li>
+    <li>
+        <i class="fa fa-pied-piper-pp"></i>
+        <div class="icon-title">fa-pied-piper-pp</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest"></i>
+        <div class="icon-title">fa-pinterest</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest-p"></i>
+        <div class="icon-title">fa-pinterest-p</div>
+    </li>
+    <li>
+        <i class="fa fa-pinterest-square"></i>
+        <div class="icon-title">fa-pinterest-square</div>
+    </li>
+    <li>
+        <i class="fa fa-product-hunt"></i>
+        <div class="icon-title">fa-product-hunt</div>
+    </li>
+    <li>
+        <i class="fa fa-qq"></i>
+        <div class="icon-title">fa-qq</div>
+    </li>
+    <li>
+        <i class="fa fa-quora"></i>
+        <div class="icon-title">fa-quora</div>
+    </li>
+    <li>
+        <i class="fa fa-ra"></i>
+        <div class="icon-title">fa-ra</div>
+    </li>
+    <li>
+        <i class="fa fa-ravelry"></i>
+        <div class="icon-title">fa-ravelry</div>
+    </li>
+    <li>
+        <i class="fa fa-rebel"></i>
+        <div class="icon-title">fa-rebel</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit"></i>
+        <div class="icon-title">fa-reddit</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit-alien"></i>
+        <div class="icon-title">fa-reddit-alien</div>
+    </li>
+    <li>
+        <i class="fa fa-reddit-square"></i>
+        <div class="icon-title">fa-reddit-square</div>
+    </li>
+    <li>
+        <i class="fa fa-renren"></i>
+        <div class="icon-title">fa-renren</div>
+    </li>
+    <li>
+        <i class="fa fa-resistance"></i>
+        <div class="icon-title">fa-resistance</div>
+    </li>
+    <li>
+        <i class="fa fa-safari"></i>
+        <div class="icon-title">fa-safari</div>
+    </li>
+    <li>
+        <i class="fa fa-scribd"></i>
+        <div class="icon-title">fa-scribd</div>
+    </li>
+    <li>
+        <i class="fa fa-sellsy"></i>
+        <div class="icon-title">fa-sellsy</div>
+    </li>
+    <li>
+        <i class="fa fa-share-alt"></i>
+        <div class="icon-title">fa-share-alt</div>
+    </li>
+    <li>
+        <i class="fa fa-share-alt-square"></i>
+        <div class="icon-title">fa-share-alt-square</div>
+    </li>
+    <li>
+        <i class="fa fa-shirtsinbulk"></i>
+        <div class="icon-title">fa-shirtsinbulk</div>
+    </li>
+    <li>
+        <i class="fa fa-simplybuilt"></i>
+        <div class="icon-title">fa-simplybuilt</div>
+    </li>
+    <li>
+        <i class="fa fa-skyatlas"></i>
+        <div class="icon-title">fa-skyatlas</div>
+    </li>
+    <li>
+        <i class="fa fa-skype"></i>
+        <div class="icon-title">fa-skype</div>
+    </li>
+    <li>
+        <i class="fa fa-slack"></i>
+        <div class="icon-title">fa-slack</div>
+    </li>
+    <li>
+        <i class="fa fa-slideshare"></i>
+        <div class="icon-title">fa-slideshare</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat"></i>
+        <div class="icon-title">fa-snapchat</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat-ghost"></i>
+        <div class="icon-title">fa-snapchat-ghost</div>
+    </li>
+    <li>
+        <i class="fa fa-snapchat-square"></i>
+        <div class="icon-title">fa-snapchat-square</div>
+    </li>
+    <li>
+        <i class="fa fa-soundcloud"></i>
+        <div class="icon-title">fa-soundcloud</div>
+    </li>
+    <li>
+        <i class="fa fa-spotify"></i>
+        <div class="icon-title">fa-spotify</div>
+    </li>
+    <li>
+        <i class="fa fa-stack-exchange"></i>
+        <div class="icon-title">fa-stack-exchange</div>
+    </li>
+    <li>
+        <i class="fa fa-stack-overflow"></i>
+        <div class="icon-title">fa-stack-overflow</div>
+    </li>
+    <li>
+        <i class="fa fa-steam"></i>
+        <div class="icon-title">fa-steam</div>
+    </li>
+    <li>
+        <i class="fa fa-steam-square"></i>
+        <div class="icon-title">fa-steam-square</div>
+    </li>
+    <li>
+        <i class="fa fa-stumbleupon"></i>
+        <div class="icon-title">fa-stumbleupon</div>
+    </li>
+    <li>
+        <i class="fa fa-stumbleupon-circle"></i>
+        <div class="icon-title">fa-stumbleupon-circle</div>
+    </li>
+    <li>
+        <i class="fa fa-superpowers"></i>
+        <div class="icon-title">fa-superpowers</div>
+    </li>
+    <li>
+        <i class="fa fa-telegram"></i>
+        <div class="icon-title">fa-telegram</div>
+    </li>
+    <li>
+        <i class="fa fa-tencent-weibo"></i>
+        <div class="icon-title">fa-tencent-weibo</div>
+    </li>
+    <li>
+        <i class="fa fa-themeisle"></i>
+        <div class="icon-title">fa-themeisle</div>
+    </li>
+    <li>
+        <i class="fa fa-trello"></i>
+        <div class="icon-title">fa-trello</div>
+    </li>
+    <li>
+        <i class="fa fa-tripadvisor"></i>
+        <div class="icon-title">fa-tripadvisor</div>
+    </li>
+    <li>
+        <i class="fa fa-tumblr"></i>
+        <div class="icon-title">fa-tumblr</div>
+    </li>
+    <li>
+        <i class="fa fa-tumblr-square"></i>
+        <div class="icon-title">fa-tumblr-square</div>
+    </li>
+    <li>
+        <i class="fa fa-twitch"></i>
+        <div class="icon-title">fa-twitch</div>
+    </li>
+    <li>
+        <i class="fa fa-twitter"></i>
+        <div class="icon-title">fa-twitter</div>
+    </li>
+    <li>
+        <i class="fa fa-twitter-square"></i>
+        <div class="icon-title">fa-twitter-square</div>
+    </li>
+    <li>
+        <i class="fa fa-usb"></i>
+        <div class="icon-title">fa-usb</div>
+    </li>
+    <li>
+        <i class="fa fa-viacoin"></i>
+        <div class="icon-title">fa-viacoin</div>
+    </li>
+    <li>
+        <i class="fa fa-viadeo"></i>
+        <div class="icon-title">fa-viadeo</div>
+    </li>
+    <li>
+        <i class="fa fa-viadeo-square"></i>
+        <div class="icon-title">fa-viadeo-square</div>
+    </li>
+    <li>
+        <i class="fa fa-vimeo"></i>
+        <div class="icon-title">fa-vimeo</div>
+    </li>
+    <li>
+        <i class="fa fa-vimeo-square"></i>
+        <div class="icon-title">fa-vimeo-square</div>
+    </li>
+    <li>
+        <i class="fa fa-vine"></i>
+        <div class="icon-title">fa-vine</div>
+    </li>
+    <li>
+        <i class="fa fa-vk"></i>
+        <div class="icon-title">fa-vk</div>
+    </li>
+    <li>
+        <i class="fa fa-wechat"></i>
+        <div class="icon-title">fa-wechat</div>
+    </li>
+    <li>
+        <i class="fa fa-weibo"></i>
+        <div class="icon-title">fa-weibo</div>
+    </li>
+    <li>
+        <i class="fa fa-weixin"></i>
+        <div class="icon-title">fa-weixin</div>
+    </li>
+    <li>
+        <i class="fa fa-whatsapp"></i>
+        <div class="icon-title">fa-whatsapp</div>
+    </li>
+    <li>
+        <i class="fa fa-wikipedia-w"></i>
+        <div class="icon-title">fa-wikipedia-w</div>
+    </li>
+    <li>
+        <i class="fa fa-windows"></i>
+        <div class="icon-title">fa-windows</div>
+    </li>
+    <li>
+        <i class="fa fa-wordpress"></i>
+        <div class="icon-title">fa-wordpress</div>
+    </li>
+    <li>
+        <i class="fa fa-wpbeginner"></i>
+        <div class="icon-title">fa-wpbeginner</div>
+    </li>
+    <li>
+        <i class="fa fa-wpexplorer"></i>
+        <div class="icon-title">fa-wpexplorer</div>
+    </li>
+    <li>
+        <i class="fa fa-wpforms"></i>
+        <div class="icon-title">fa-wpforms</div>
+    </li>
+    <li>
+        <i class="fa fa-xing"></i>
+        <div class="icon-title">fa-xing</div>
+    </li>
+    <li>
+        <i class="fa fa-xing-square"></i>
+        <div class="icon-title">fa-xing-square</div>
+    </li>
+    <li>
+        <i class="fa fa-y-combinator"></i>
+        <div class="icon-title">fa-y-combinator</div>
+    </li>
+    <li>
+        <i class="fa fa-y-combinator-square"></i>
+        <div class="icon-title">fa-y-combinator-square</div>
+    </li>
+    <li>
+        <i class="fa fa-yahoo"></i>
+        <div class="icon-title">fa-yahoo</div>
+    </li>
+    <li>
+        <i class="fa fa-yc"></i>
+        <div class="icon-title">fa-yc</div>
+    </li>
+    <li>
+        <i class="fa fa-yc-square"></i>
+        <div class="icon-title">fa-yc-square</div>
+    </li>
+    <li>
+        <i class="fa fa-yelp"></i>
+        <div class="icon-title">fa-yelp</div>
+    </li>
+    <li>
+        <i class="fa fa-yoast"></i>
+        <div class="icon-title">fa-yoast</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube"></i>
+        <div class="icon-title">fa-youtube</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube-play"></i>
+        <div class="icon-title">fa-youtube-play</div>
+    </li>
+    <li>
+        <i class="fa fa-youtube-square"></i>
+        <div class="icon-title">fa-youtube-square</div>
+    </li>
+    <li>
+        <i class="fa fa-ambulance"></i>
+        <div class="icon-title">fa-ambulance</div>
+    </li>
+    <li>
+        <i class="fa fa-h-square"></i>
+        <div class="icon-title">fa-h-square</div>
+    </li>
+    <li>
+        <i class="fa fa-heart"></i>
+        <div class="icon-title">fa-heart</div>
+    </li>
+    <li>
+        <i class="fa fa-heart-o"></i>
+        <div class="icon-title">fa-heart-o</div>
+    </li>
+    <li>
+        <i class="fa fa-heartbeat"></i>
+        <div class="icon-title">fa-heartbeat</div>
+    </li>
+    <li>
+        <i class="fa fa-hospital-o"></i>
+        <div class="icon-title">fa-hospital-o</div>
+    </li>
+    <li>
+        <i class="fa fa-medkit"></i>
+        <div class="icon-title">fa-medkit</div>
+    </li>
+    <li>
+        <i class="fa fa-plus-square"></i>
+        <div class="icon-title">fa-plus-square</div>
+    </li>
+    <li>
+        <i class="fa fa-stethoscope"></i>
+        <div class="icon-title">fa-stethoscope</div>
+    </li>
+    <li>
+        <i class="fa fa-user-md"></i>
+        <div class="icon-title">fa-user-md</div>
+    </li>
+    <li>
+        <i class="fa fa-wheelchair"></i>
+        <div class="icon-title">fa-wheelchair</div>
+    </li>
+    <li>
+        <i class="fa fa-wheelchair-alt"></i>
+        <div class="icon-title">fa-wheelchair-alt</div>
+    </li>
+</ul>
+
+<script src="__ROOT__/static/plugs/jquery/jquery.min.js" type="text/javascript"></script>
+<script>
+    $(function () {
+        $('li').on('click', function (className) {
+            className = $(this).find('i').get(0).className;
+            if (className) {
+                top.$('[name="{$field}"]').val(className).trigger('change');
+                top.layer.close(top.layer.getFrameIndex(window.name));
+            }
+        });
+    });
+</script>
+
+</body>
+</html>

+ 116 - 0
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}

+ 30 - 0
application/admin/view/auth/form.html

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

+ 80 - 0
application/admin/view/config/info.html

@@ -0,0 +1,80 @@
+{extend name="main"}
+
+{block name="button"}
+
+{if auth('config')}
+<a class="layui-btn layui-btn-sm layui-btn-primary" data-modal="{:url('config')}">修改系统配置</a>
+{/if}
+
+{/block}
+
+{block name="content"}
+
+<div class="think-box-shadow margin-bottom-15">
+    <span class="color-green font-w7 text-middle">文件存储引擎:</span>
+    {foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','oss'=>'阿里云OSS存储'] as $k=>$v}
+    {if sysconf('storage_type') eq $k}
+    {if auth('file')}<a data-modal="{:url('file')}?type={$k}" class="layui-btn layui-btn-sm">{$v}</a>{else}<a class="layui-btn layui-btn-sm">{$v}</a>{/if}
+    {elseif auth('file')}<a data-modal="{:url('file')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
+    {/foreach}
+</div>
+
+<div class="think-box-shadow padding-40">
+    <div class="layui-form-item">
+        <span class="color-green font-w7">网站名称 Website</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('site_name')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('site_name')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">网站名称及网站图标,将显示在浏览器的标签上</p>
+    </div>
+    <div class="layui-form-item">
+        <span class="color-green font-w7">管理程序名称 Name</span>
+        <label class="relative block">
+            <input readonly placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('app_name')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">管理程序名称,将显示在后台左上角标题</p>
+    </div>
+    <div class="layui-form-item">
+        <span class="color-green font-w7">管理程序版本 Version</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('app_version')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('app_version')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">管理程序版本,将显示在后台左上角标题</p>
+    </div>
+
+    <div class="layui-form-item">
+        <span class="color-green font-w7">网站备案号 Miitbeian</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('miitbeian')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('miitbeian')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">网站备案号,可以在<a target="_blank" href="http://beian.miit.gov.cn">备案管理中心</a>查询获取,将显示在登录页面下面</p>
+    </div>
+    <div class="layui-form-item">
+        <span class="color-green font-w7">网站版权信息 Copyright</span>
+        <label class="relative block">
+            <input readonly value="{:sysconf('site_copy')}" class="layui-input layui-bg-gray">
+            <a data-copy="{:sysconf('site_copy')}" class="fa fa-copy right-btn"></a>
+        </label>
+        <p class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统</p>
+    </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}

+ 20 - 0
application/admin/view/config/storage-local.html

@@ -0,0 +1,20 @@
+<form onsubmit="return false;" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p>文件将存储在本地服务器,需确保服务器的 public/upload 目录有写入权限,有足够的存储空间!</p>
+        </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 padding-left-40">
+            <input type="hidden" name="storage_type" value="local">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+</form>

+ 80 - 0
application/admin/view/config/storage-oss.html

@@ -0,0 +1,80 @@
+<form onsubmit="return false;" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p class="margin-bottom-5 font-w7">文件将上传到阿里云OSS空间,需要配置OSS公开访问及跨域策略!</p>
+            目前已实现自动创建空间及配置访问策略!<a target="_blank" href="https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=08p1pddw">我要免费申请</a>
+        </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="30" 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 padding-left-40">
+            <input type="hidden" name="storage_type" value="oss">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+    <script>form.render()</script>
+</form>

+ 80 - 0
application/admin/view/config/storage-qiniu.html

@@ -0,0 +1,80 @@
+<form onsubmit="return false" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body">
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code" style="border-left-width:1px;background:none">
+            <p class="margin-bottom-5 font-w7">文件将上传到七牛云存储,对象存储需要配置为公开访问的Bucket空间!</p>
+            完成实名认证后可获得10G免费存储空间哦!<a target="_blank" href="https://portal.qiniu.com/signup?code=1hefnmobzees2">我要免费申请</a>
+        </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">七牛云存储访问协议,其中 https 需要配置证书才能使用,auto 为相对协议。</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 padding-left-40">
+            <input type="hidden" name="storage_type" value="qiniu">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+</form>

+ 57 - 0
application/admin/view/config/system-config.html

@@ -0,0 +1,57 @@
+<form onsubmit="return false" data-auto="true" action="{:url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body padding-left-40">
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">网站名称 Website</span>
+                <input name="site_name" required placeholder="请输入网站名称" value="{:sysconf('site_name')}" class="layui-input">
+            </label>
+            <p class="help-block">网站名称,将在浏览器的标签上显示名称</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">管理程序名称 Name</span>
+                <input name="app_name" required placeholder="请输入程序名称" value="{:sysconf('app_name')}" class="layui-input">
+            </label>
+            <p class="help-block">管理程序名称,在后台左上角标题处理显示</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">管理程序版本 Version</span>
+                <input name="app_version" placeholder="请输入程序版本" value="{:sysconf('app_version')}" class="layui-input">
+            </label>
+            <p class="help-block">管理程序版本,在后台左上角标题处理显示</p>
+        </div>
+        <div class="layui-form-item">
+            <span class="color-green font-w7">浏览器图标 Browser</span>
+            <div class="relative block">
+                <img alt="icon" data-tips-image style="height:auto;max-height:42px;min-width:42px" 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 图标的尺寸为 128x128 <a href="http://www.favicon-icon-generator.com" target="_blank">ICON在线制作</a></p>
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">网站备案号 Miitbeian</span>
+                <input name="miitbeian" required placeholder="请输入网站备案号" value="{:sysconf('miitbeian')}" class="layui-input">
+            </label>
+            <p class="help-block">网站备案号,可以在<a target="_blank" href="http://beian.miit.gov.cn">备案管理中心</a>查询获取,将在登录页面下面显示</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">网站版权信息 Copyright</span>
+                <input name="site_copy" required placeholder="请输入版权信息" value="{:sysconf('site_copy')}" class="layui-input">
+            </label>
+            <p class="help-block">网站版权信息,在后台登录页面显示版本信息并链接到备案到信息备案管理系统</p>
+        </div>
+
+        <div class="hr-line-dashed"></div>
+
+        <div class="layui-form-item text-center">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+    </div>
+
+</form>

+ 134 - 0
application/admin/view/index/index.html

@@ -0,0 +1,134 @@
+<!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>
+
+    <style>
+        .layui-header .layui-layout-right li a{
+            padding-right: 35px;
+        }
+        .tangram-suggestion-main{
+            z-index: 999;
+        }
+    </style>
+    <script src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=E4Y9cdBjAvDM6DjGcOmBA4v2GcEXAWvG"></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.user.username'}
+            <li class="layui-nav-item">
+                <dl class="layui-nav-child">
+                    <dd lay-unselect><a data-modal="{:url('admin/index/info',['id'=>session('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('user.id')])}"><i class="layui-icon layui-icon-component margin-right-5"></i>安全设置</a></dd>
+                    {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}
+                    {notempty name='GLOBALS.AdminUserRightOption'}{foreach $GLOBALS.AdminUserRightOption as $option}{if auth($option.node)}
+                    <dd lay-unselect><a data-{$option.type}="{$option.action}"><i class="{$option.icon} margin-right-5"></i>{$option.title}</a></dd>
+                    {/if}{/foreach}{/notempty}
+                    <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('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>

+ 228 - 0
application/admin/view/index/main.html

@@ -0,0 +1,228 @@
+{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>{$data.user_num}</div>
+                <div>当前会员数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-username"></i>
+        </div>
+
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#57bdbf,#2f9de2)">
+                <div>新增会员数量</div>
+                <div>{$data.new_user}</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(-125deg,#57bdbf,#2f9de2)">
+                <div>区域代理数量</div>
+                <div>{$data.agency_num}</div>
+                <div>区域代理数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-group"></i>
+        </div>
+
+        <div class="layui-col-sm6 layui-col-md3">
+            <div class="store-total-item nowrap" style="background:linear-gradient(-125deg,#57bdbf,#2f9de2)">
+                <div>分销商数量</div>
+                <div>{$data.partner_num}</div>
+                <div>分销商数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-friends"></i>
+        </div>
+    </div>
+</div>
+
+<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,#ff7d7d,#fb2c95)">
+                <div>商品数量</div>
+                <div>{$data.goods_num}</div>
+                <div>当前商品总数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-vercode"></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>{$data.order_num}</div>
+                <div>当前支付订单总数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-vercode"></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>{$data.order_money}</div>
+                <div>当前商城订单交易金额</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-dollar"></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>{$data.gift_order_num}</div>
+                <div>定制订单量数量(所有的)</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-list"></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>{$data.gift_order_money}</div>
+                <div>定制订单量交易金额</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-dollar"></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>{$data.news_num}</div>
+                <div>资讯数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-survey"></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>{$data.video_num}</div>
+                <div>视频专栏视频数量</div>
+            </div>
+            <i class="store-total-icon layui-icon layui-icon-video"></i>
+        </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>多端商城</td>
+                </tr>
+                <tr>
+                    <td>在线体验</td>
+                    <td><a target="_blank" href="http://ddsc.hdlkeji.com">http://ddsc.hdlkeji.com</a></td>
+                </tr>
+                <tr>
+                    <td>项目地址</td>
+                    <td><a target="_blank" href="http://ddsc.hdlkeji.com">http://ddsc.hdlkeji.com</a></td>
+                </tr>
+                <tr>
+                    <td>BUG反馈</td>
+                    <td><a target="_blank" href="http://ddsc.hdlkeji.com">http://ddsc.hdlkeji.com</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.hdl.com</a></td>
+                </tr>
+                <tr>
+                    <td>办公地址</td>
+                    <td>临沂市北城新区环球中心1707</td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+</div>
+{/block}

+ 57 - 0
application/admin/view/login/index.html

@@ -0,0 +1,57 @@
+{extend name="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="登录账号" title="请输入登录账号">
+                </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="登录密码" title="请输入登录密码">
+                </label>
+            </li>
+            <li class="verify layui-hide">
+                <label class="inline-block relative">
+                    <i class="layui-icon layui-icon-picture-fine"></i>
+                    <input class="layui-input" required pattern="^\S{4,}$" name="verify" maxlength="4" autocomplete="off" placeholder="验证码" title="请输入验证码">
+                </label>
+                <label data-captcha="{:url('admin/login/captcha',[],false)}" data-field-verify="verify" data-field-uniqid="uniqid" data-captcha-type="{$captcha_type}" data-captcha-token="{$captcha_token}"></label>
+            </li>
+            <li class="text-center padding-top-20">
+                <button type="submit" class="layui-btn layui-disabled full-width" data-form-loaded="立即登入">正在载入</button>
+            </li>
+        </ul>
+    </form>
+    <div class="footer notselect">
+        <p class="layui-hide-xs"><a target="_blank" href="https://www.google.cn/chrome">推荐使用谷歌浏览器</a></p>
+        {:sysconf('site_copy')}
+        {if sysconf('miitbeian')}<span class="padding-5">|</span><a target="_blank" href="http://beian.miit.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/login.js"></script>
+<script src="__ROOT__/static/plugs/supersized/supersized.3.2.7.min.js"></script>
+{/block}

+ 11 - 0
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>

+ 89 - 0
application/admin/view/menu/form.html

@@ -0,0 +1,89 @@
+<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' lay-search>
+                    <!--{foreach $menus as $menu}-->
+                    <!--{eq name='menu.id' value='$vo.pid|default=0'}-->
+                    <option selected value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{else}-->
+                    <option value='{$menu.id}'>{$menu.spl|raw}{$menu.title}</option>
+                    <!--{/eq}-->
+                    <!--{/foreach}-->
+                </select>
+                <p class="help-block">必选,请选择上级菜单或顶级菜单(目前最多支持三级菜单)</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">必填,请填写菜单名称(如:系统管理),建议字符不要太长,一般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">
+                    必填,请填写系统节点(如: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">可选,设置菜单链接的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">可选,设置菜单选项前置图标,目前只支持 Font Awesome 5.2.0 字体图标</p>
+            </div>
+        </div>
+
+    </div>
+
+    <div class="hr-line-dashed"></div>
+    {notempty name='vo.id'}<input type='hidden' value='{$vo.id}' name='id'>{/notempty}
+
+    <div class="layui-form-item text-center">
+        <button class="layui-btn" type='submit'>保存数据</button>
+        <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消编辑吗?" data-close>取消编辑</button>
+    </div>
+
+</form>
+
+{block name='script'}
+<script>
+    require(['jquery.autocompleter'], function () {
+        form.render();
+        $('[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 - 0
application/admin/view/menu/index.html

@@ -0,0 +1,80 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("add")}
+<button data-modal='{:url("add")}' data-title="添加菜单" class='layui-btn layui-btn-sm layui-btn-primary'>添加菜单</button>
+{/if}
+
+{if auth("remove")}
+<button data-action='{:url("remove")}' data-csrf="{:systoken('remove')}" data-rule="id#{key}" class='layui-btn layui-btn-sm layui-btn-primary'>删除菜单</button>
+{/if}
+
+{/block}
+
+{block name="content"}
+<div class="think-box-shadow">
+    {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("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("edit")}
+                <a data-dbclick class="layui-btn layui-btn-xs" data-title="编辑菜单" data-modal='{:url("edit")}?id={$vo.id}'>编 辑</a>
+                {/if}
+
+                {if $vo.status eq 1 and auth("forbid")}
+                <a class="layui-btn layui-btn-warm layui-btn-xs" data-confirm="确定要禁用菜单吗?" data-action="{:url('forbid')}" data-value="id#{$vo.ids};status#0" data-csrf="{:systoken('forbid')}">禁 用</a>
+                {elseif auth("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('resume')}">启 用</a>
+                {/if}
+
+                {if auth("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('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+    {/empty}
+</div>
+{/block}

+ 18 - 0
application/admin/view/official/index-about-us.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">关于我们</span><span class="nowrap color-desc">AboutUs</span>
+            <textarea name="about_us">{:sysconf('about_us')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="about_us"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-agent-notice.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">代理商须知</span><span class="nowrap color-desc">AgentNotice</span>
+            <textarea name="agent_notice">{:sysconf('agent_notice')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="agent_notice"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-agreement.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">用户协议</span><span class="nowrap color-desc">Agreement</span>
+            <textarea name="agreement">{:sysconf('agreement')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="agreement"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-customer-service.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">客服设置</span><span class="nowrap color-desc">CustomerService</span>
+            <textarea name="customer_service">{:sysconf('customer_service')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="customer_service"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-integral-channel.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">会员权益</span><span class="nowrap color-desc">IntegralChannel</span>
+            <textarea name="integral_channel">{:sysconf('integral_channel')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="integral_channel"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-partner-item.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">分销条款</span><span class="nowrap color-desc">PartnerItem</span>
+            <textarea name="partner_item">{:sysconf('partner_item')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="partner_item"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-privacy.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">隐私政策</span><span class="nowrap color-desc">Privacy</span>
+            <textarea name="privacy">{:sysconf('privacy')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="privacy"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-refund-desc.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">退款退货说明</span><span class="nowrap color-desc">RefundDesc</span>
+            <textarea name="refund_desc">{:sysconf('refund_desc')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="refund_desc"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-sign-rule.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">签到规则</span><span class="nowrap color-desc">SignRule</span>
+            <textarea name="sign_rule">{:sysconf('sign_rule')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="sign_rule"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-user-equity.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">会员权益</span><span class="nowrap color-desc">UserEquity</span>
+            <textarea name="user_equity">{:sysconf('user_equity')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="user_equity"]', {height: 500});
+        })
+    </script>
+</form>

+ 18 - 0
application/admin/view/official/index-write-off.html

@@ -0,0 +1,18 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+        <label class="layui-form-item margin-top-20 block relative">
+            <span class="color-green margin-right-10">注销须知</span><span class="nowrap color-desc">WriteOff</span>
+            <textarea name="write_off">{:sysconf('write_off')}</textarea>
+        </label>
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+    <script>
+        window.form.render();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="write_off"]', {height: 500});
+        })
+    </script>
+</form>

+ 48 - 0
application/admin/view/official/index.html

@@ -0,0 +1,48 @@
+{extend name="admin@main"}
+
+{block name="content"}
+
+<div class="layui-tab layui-tab-card think-bg-white">
+    <ul class="layui-tab-title notselect">
+        <li data-type="store-config-type-sms1">配置信息</li>
+        <li data-type="store-config-type-sms2">用户协议</li>
+        <li data-type="store-config-type-sms2">关于我们</li>
+        <li data-type="store-config-type-sms2">隐私政策</li>
+        <li data-type="store-config-type-sms2">代理商须知</li>
+        <li data-type="store-config-type-sms2">分销条款</li>
+        <li data-type="store-config-type-sms2">退款退货说明</li>
+        <li data-type="store-config-type-sms2">会员权益</li>
+        <li data-type="store-config-type-sms2">积分获取方式</li>
+        <li data-type="store-config-type-sms2">签到规则</li>
+        <li data-type="store-config-type-sms2">注销须知</li>
+        <li data-type="store-config-type-sms2">客服设置</li>
+    </ul>
+    <div class="layui-tab-content">
+        <div class="layui-tab-item">{include file='official/platform-set'}</div>
+        <div class="layui-tab-item">{include file='official/index-agreement'}</div>
+        <div class="layui-tab-item">{include file='official/index-about-us'}</div>
+        <div class="layui-tab-item">{include file='official/index-privacy'}</div>
+        <div class="layui-tab-item">{include file='official/index-agent-notice'}</div>
+        <div class="layui-tab-item">{include file='official/index-partner-item'}</div>
+        <div class="layui-tab-item">{include file='official/index-refund-desc'}</div>
+        <div class="layui-tab-item">{include file='official/index-user-equity'}</div>
+        <div class="layui-tab-item">{include file='official/index-integral-channel'}</div>
+        <div class="layui-tab-item">{include file='official/index-sign-rule'}</div>
+        <div class="layui-tab-item">{include file='official/index-write-off'}</div>
+        <div class="layui-tab-item">{include file='official/index-customer-service'}</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')});
+        });
+    })('store-config-type');
+</script>
+{/block}

+ 32 - 0
application/admin/view/official/platform-set.html

@@ -0,0 +1,32 @@
+<form onsubmit="return false;" data-auto="true" action="{:url('save')}" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body padding-40">
+
+        <label class="layui-form-item block relative">
+            <span class="color-green margin-right-10">首页公告</span><span class="nowrap color-desc">IndexNotice</span>
+            <input name="index_notice"   required placeholder="请输首页公告内容" value="{:sysconf('index_notice')}" class="layui-input">
+        </label>
+
+        <div class="layui-form-item text-center margin-top-20">
+            <button class="layui-btn" type="submit">保存配置</button>
+        </div>
+    </div>
+</form>
+<script>
+    layui.use('laydate', function(){
+        var laydate = layui.laydate;
+        //时间选择器
+        laydate.render({
+            elem: '#start_time_cost'
+            ,type: 'time'
+        });
+        laydate.render({
+            elem: '#end_time_cost'
+            ,type: 'time'
+        });
+    })
+
+
+
+
+</script>

+ 68 - 0
application/admin/view/oplog/index.html

@@ -0,0 +1,68 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("clear")}
+<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
+{/if}
+
+{if auth("remove")}
+<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('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></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">
+                <span class="font-w7">{$vo.username|default='-'}</span><br>
+                <span class="color-desc">{$vo.node|default='-'}</span>
+            </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("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('remove')}">删 除</a>
+                {/if}
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+        {/notempty}
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+
+{/block}

+ 56 - 0
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>

+ 73 - 0
application/admin/view/user/form.html

@@ -0,0 +1,73 @@
+<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post" autocomplete="off">
+    <div class="layui-card-body padding-left-40">
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">登录用户账号</span>
+                <span class="color-desc margin-left-5">Username</span>
+                {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}
+            </label>
+            <p class="help-block">登录用户账号创建后,不允许再次修改。</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">用户联系手机</span>
+                <span class="color-desc margin-left-5">Phone</span>
+                <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">
+            </label>
+            <p class="color-desc">可选,用户联系手机号码,需要填写正确的格式</p>
+        </div>
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">联系电子邮箱</span>
+                <span class="color-desc margin-left-5">Email</span>
+                <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">
+            </label>
+            <p class="color-desc">可选,用户联系电子邮箱,需要填写正确的格式</p>
+        </div>
+
+        {notempty name='authorizes'}
+        <div class="layui-form-item relative">
+            <span class="color-green font-w7">角色访问授权</span>
+            <span class="color-desc margin-left-5">Authorization</span>
+            <div class="layui-textarea">
+                {if isset($vo.username) and $vo.username eq 'admin'}
+                <span class="color-desc">超级用户不需要配置权限</span>
+                {elseif empty($authorizes)}
+                <span class="color-desc">未配置权限</span>
+                {else}
+                {foreach $authorizes as $authorize}
+                <label class="think-checkbox layui-unselect">
+                    {if in_array($authorize.id, $vo.authorize)}
+                    <input type="checkbox" checked name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    {else}
+                    <input type="checkbox" name="authorize[]" value="{$authorize.id}" lay-ignore> {$authorize.title}
+                    {/if}
+                </label>
+                {/foreach}
+                {/if}
+            </div>
+        </div>
+        {/notempty}
+
+        <div class="layui-form-item">
+            <label class="relative block">
+                <span class="color-green font-w7">用户身份描述</span>
+                <span class="color-desc margin-left-5">Description</span>
+                <textarea placeholder="请输入用户身份描述" class="layui-textarea" name="desc">{$vo.desc|default=""}</textarea>
+            </label>
+        </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>

+ 77 - 0
application/admin/view/user/index.html

@@ -0,0 +1,77 @@
+{extend name='main'}
+
+{block name="button"}
+
+{if auth("add")}
+<button data-modal='{:url("add")}' data-title="添加用户" class='layui-btn layui-btn-sm layui-btn-primary'>添加用户</button>
+{/if}
+
+{if auth("remove")}
+<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('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("pass")}
+                <a class="layui-btn layui-btn-normal layui-btn-sm" data-title="设置密码" data-modal='{:url("pass")}?id={$vo.id}'>密 码</a>
+                {/if}
+
+                {if auth("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("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('forbid')}">禁 用</a>
+                {elseif $vo.status eq 0 and auth("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('resume')}">启 用</a>
+                {/if}
+
+                {if auth("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('remove')}">删 除</a>
+                {/if}
+
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+
+    {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+
+</div>
+
+{/block}

+ 57 - 0
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>

+ 57 - 0
application/admin/view/user/pass.html

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

+ 33 - 0
application/admin/view/versions/form.html

@@ -0,0 +1,33 @@
+<form onsubmit="return false;" action="{:request()->url()}" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
+
+    <div class="layui-card-body">
+
+
+        <div class="layui-row margin-bottom-15">
+            <label class="layui-form-label label-required">版本號</label>
+            <div class="layui-input-block">
+                <input name="title" required value='{$vo.title|default=""}' placeholder="請輸入版本號" class="layui-input">
+            </div>
+        </div>
+
+        <div class="layui-row margin-bottom-15">
+            <label class="layui-form-label label-required">修改內容</label>
+            <div class="layui-input-block">
+                <textarea name="content">{$vo.content|default=''|raw}</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();
+        require(['ckeditor', 'angular'], function () {
+            window.createEditor('[name="content"]', {height: 260});
+        })
+    </script>
+</form>

+ 45 - 0
application/admin/view/versions/index.html

@@ -0,0 +1,45 @@
+{extend name='admin@main'}
+
+
+{block name="content"}
+<div class="think-box-shadow">
+
+    <table class="layui-table margin-top-10" lay-skin="line">
+        {notempty name='list'}
+        <thead>
+        <tr>
+
+            <th class='text-left nowrap'>系統類型</th>
+            <th class='text-left nowrap'>版本號</th>
+            <th class="text-center">狀態</th>
+            <th class="text-center">時間</th>
+            <th class="text-center">操作</th>
+        </tr>
+        </thead>
+        {/notempty}
+        <tbody>
+        {foreach $list as $key=>$vo}
+        <tr>
+            <td class='text-left nowrap'>
+                {if $vo.type == 1} 安卓 {else} IOS {/if}
+            </td>
+            <td class='text-left nowrap'>
+
+                {$vo.title|default=''}
+            </td>
+            <td class='text-center nowrap'>
+                {eq name='vo.status' value='0'}<span class="layui-badge">已禁用</span>{else}<span class="layui-badge layui-bg-green">使用中</span>{/eq}<br>
+            </td>
+            <td class='text-center nowrap'>{$vo.create_at|format_datetime}</td>
+            <td class='text-center nowrap'>
+                {if auth("store/versions/edit")}
+                <a data-title="編輯版本" class="layui-btn layui-btn-sm" data-modal='{:url("edit")}?id={$vo.id}'>編 輯</a>
+                {/if}
+            </td>
+        </tr>
+        {/foreach}
+        </tbody>
+    </table>
+    {empty name='list'}<span class="notdata">沒有記錄哦</span>{else}{$pagehtml|raw|default=''}{/empty}
+</div>
+{/block}

+ 41 - 0
application/api/common.php

@@ -0,0 +1,41 @@
+<?php
+// 接口公共方法
+use think\Db;
+function get_order_sn(){
+    $order_id_main = date('YmdHis') . rand(10000000,99999999);
+    $order_id_len = strlen($order_id_main);
+    $order_id_sum = 0;
+    for($i=0; $i<$order_id_len; $i++){
+        $order_id_sum += (int)(substr($order_id_main,$i,1));
+    }
+    $osn = $order_id_main . str_pad((100 - $order_id_sum % 100) % 100,2,'0',STR_PAD_LEFT);
+    return $osn;
+}
+
+function encrypt_password($password){
+    return password_hash($password,PASSWORD_DEFAULT);
+}
+
+function check_password($password,$hash)
+{
+    return password_verify($password,$hash);
+}
+// 获取日历 默认最近7天
+function get_calendar($day = 7,$type='asc'){
+    $data = [];
+    $week_arr = ['日','一','二','三','四','五','六'];
+    for($i=0;$i<$day;$i++) {
+        $day_time = date('Y-m-d',strtotime("-$i days"));
+        $day_title= trim(date('m月d日',strtotime("-$i days")),'0');
+        $time_int = strtotime($day_time);
+        $week_day =$week_arr[date('w',strtotime($day_time))];
+        $data[] = ['day_time' => $day_time,'week_day'=>$week_day,'time_int'=>$time_int,'day_title'=>$day_title];
+    }
+   if($type == 'asc') array_multisort(array_column($data,'time_int'),SORT_ASC,$data);
+   return $data;
+}
+
+
+
+
+

+ 380 - 0
application/api/controller/Alipay.php

@@ -0,0 +1,380 @@
+<?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\api\controller;
+
+use app\api\controller\Base;
+use think\Controller;
+use think\Db;
+use think\Model;
+
+use Alipay\EasySDK\Kernel\Factory;
+use Alipay\EasySDK\Kernel\Util\ResponseChecker;
+use Alipay\EasySDK\Kernel\Config;
+/**
+ * 支付宝支付
+ * Class Member
+ * @package app\api\controller
+ */
+class Alipay extends Base
+{
+    /**
+     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
+     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * 支付宝支付
+     */
+    public static function ali_pay($subject,$outTradeNo,$totalAmount,$notifyUrl){
+        Factory::setOptions(self::getOptions($notifyUrl));
+        try {
+            //2. 发起API调用(以支付能力下的统一收单交易创建接口为例)
+            //$result = Factory::payment()->common()->create("iPhone6 16G", "20200326235526001", "88.88", "2088002656718920");
+            $result = Factory::payment()->App()->pay($subject,$outTradeNo , $totalAmount);
+            $responseChecker = new ResponseChecker();
+            //3. 处理响应或异常
+            if ($responseChecker->success($result)) {
+                return $result->body;
+            } else {
+                echo "调用失败,原因:". $result->msg.",".$result->subMsg.PHP_EOL;
+            }
+        } catch (Exception $e) {
+            return false;
+        }
+    }
+    public static function ali_pay_pc($subject='商品',$outTradeNo,$totalAmount,$notifyUrl,$returnUrl){
+        Factory::setOptions(self::getOptions($notifyUrl));
+        try {
+            $result = Factory::payment()->Page()->pay($subject,$outTradeNo,$totalAmount,$returnUrl);
+            $responseChecker = new ResponseChecker();
+            //3. 处理响应或异常
+            if ($responseChecker->success($result)) {
+                return $result->body;
+            } else {
+                echo "调用失败,原因:". $result->msg.",".$result->subMsg.PHP_EOL;
+            }
+        } catch (Exception $e) {
+            return false;
+        }
+    }
+    /**
+     * 支付宝支付退款
+     */
+    public static function ali_refund($outTradeNo,$totalAmount){
+        Factory::setOptions(self::getOptions(''));
+        $result = Factory::payment()->common()->refund($outTradeNo,$totalAmount);
+        $responseChecker = new ResponseChecker();
+        return $responseChecker->success($result);
+    }
+    /**
+     * 单笔转账到支付宝账户
+     */
+    public static function ali_withdrawal($out_biz_no,$trans_amount,$identity,$name){
+        require_once env('root_path').'/vendor/aop/AopCertClient.php';
+        require_once env('root_path').'/vendor/aop/request/AlipayFundTransUniTransferRequest.php';
+        $aop = new \AopCertClient();
+        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
+        $aop->appId = '2021002142672998';
+        $aop->rsaPrivateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCTKpmmpfu6Hrn5xImo1dIQebMgJNh8KaTDdzPN6skQL8n/xELxbNZ5G1SF58H/ZzfQHaI0ZdDUhS01o7ujlh5TVdBkTEzanl2ctdFEQdCI3q6syYWs7P4gY3jLYH+XYjZs9beF3IpNRSEPj694dm3mvmVzcN9oYks2h3BNmAcbVx+IbMPRMbGKyXq2pxQguuYg+Yl7y7VpvY1h77Sve9Yi0RIf3X5VRfP95n7zT3hND56cEAAkbY+awwc8cObHQHL/rVIHyZPEPXpfUQ+afuoHO0evdCZAp+gCYlG6pPZpZ/bbKGccLoFVZhWk6qChTNoZYjS0yzE6gQmQl3xZeJSJAgMBAAECggEATWpMd5C7EdZWCKCttaX9IfOTGeaoBvC1HqnXE4xdhmlNPoFUocGaNQz+co5Oy/bVMmJUUHH638DK3nuqGky+2SG8RPaqOxqxrd0rH1frxgQ2KOi9rBDjQdBx27KAi/b7IGhFyWIRUsJ5uMDiEmFiQM6Jeae3riZ+4Elw9zBxFJz49Iv35cx5jYS5o7u1plBIZOG4ECskHr7xpb0UEaR77mfCTG7qVSuTuH3240nbW2G/hue7t5QU7y+CXUgn5c3mcpRWHu4CHpNdCf53axhE3+CrxfxyKH4/VQDaXpwnENFMoukl6ZQlbMbbZr0e0SNQizpCosqM/7kp0H2Etem6rQKBgQDsDL10rnVF4FiVC2gIGKVJTyORS5z8aZQqAGKsbyY93JkPYI2BD0ENzM2Y1NHP4AMyh7Q+WKcz/EYCL6QnGV3xWNNE/heFXRNb7cMDQsWbDpBAXj32OX3nX4ww5YTqTzXNtjVreK0WbBqLOmQF7NhIB00RA88WW/UY7pJo+p1OkwKBgQCfmr84EsK47CnekvJnX+S7R08gjC15FraEgH0Aa1b4w6fQVyanAkSa1eep9FZTpxoE7p6GJpPSiCQnE3MHzDKoQv4xoxRIXQotMhsvVAkerHge6ybQvgLCVTUEpCgMEL9uRLIL+imlazKanVBCVmac2UNGsCqkqHT0Gm6Zsp1l8wKBgF1v9Za4cCeG1Mm6yCVcTCEmuHeNLMklqcaufGCxZrvaFKRnndvWg/PIfCHhLGRS0jEwUoLTaOxFEhlPbnUjr3IXrRmEUx8xZrZe+XDS/5GPRD6Wj4Rl4Zay1bWNRP3S+QNC+wZdsHZNuHwgUvOde0eXzEPN9C1vnSePWFlByv8NAoGAFXyo16y26Fxq+pr/5Wjki037Wh9lE9M5+TavHXpV+CGnGwZQntVQVSQNDzVk1dg+SYGyd88DwakwbM5Sgy87dqmmPRp+ZYuZDiKbxFBk9es0NL1luV6LUoxUGe7bsVwj2X2IFtKz/qAi7OvW3UdygxVA2GhpJUfEjwRr9Wc1h38CgYEAyTcugtxt6WIT1MtepWwxMgasiuEQgAYY0oQ/tgPxBqZyz5Pkm9yJNsyrvgNfBZFTdexqkby80UGksXt24WsPfhVinTmtuNo8/JOgKkFU4BR3rirfqGB11o/83Z52XFne7D+rR9a1XP4mT+Q+yLQWOT0ETo2+712/+86uUW+rjj8=';
+        $aop->alipayrsaPublicKey='';
+        $aop->apiVersion = '1.0';
+        $aop->signType = 'RSA2';
+        $aop->postCharset='UTF-8';
+        $aop->format='json';
+        $aop->isCheckAlipayPublicCert = true;//是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
+        //支付宝公钥证书路径(要确保证书文件可读),例如:/home/admin/cert/alipayCertPublicKey_RSA2.crt
+        $alipayCertPath = 'ali_cert/alipayCertPublicKey_RSA2.crt';
+        //调用getPublicKey从支付宝公钥证书中提取公钥  alipayCertPath
+        $aop->alipayrsaPublicKey =$aop->getPublicKey($alipayCertPath);
+        // 应用证书路径(要确保证书文件可读),例如:/home/admin/cert/appCertPublicKey.crt
+        $appCertPath = 'ali_cert/appCertPublicKey_2021002142672998.crt';
+        //调用getCertSN获取证书序列号
+        $aop->appCertSN = $aop->getCertSN($appCertPath);
+        //支付宝根证书路径(要确保证书文件可读),例如:/home/admin/cert/alipayRootCert.crt
+        $rootCertPath  = 'ali_cert/alipayRootCert.crt';
+
+        //调用getRootCertSN获取支付宝根证书序列号
+        $aop->alipayRootCertSN = $aop->getRootCertSN($rootCertPath);
+        $orderData= array(
+            'out_biz_no' => $out_biz_no,// 订单号
+            'trans_amount' => $trans_amount,   // 提现实际金额
+            'product_code' => "TRANS_ACCOUNT_NO_PWD",
+            'biz_scene' => 'DIRECT_TRANSFER',
+            'payee_info' => [
+                'identity' => $identity,// 收款人帐户
+                'identity_type' => 'ALIPAY_LOGON_ID',
+                'name' => $name, // 收款人姓名
+            ],
+            'remark' => "提现", // 转帐备注
+        );
+        $request = new \AlipayFundTransUniTransferRequest();
+        $request->setBizContent(json_encode($orderData));
+        $result = $aop->execute($request);
+        //var_dump($result);exit();
+        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
+        $resultCode = $result->$responseNode->code;
+        if(!empty($resultCode)&&$resultCode == 10000){
+            return true;
+        } else {
+            return false;
+        }
+    }
+    public static function getOptions($notifyUrl){
+        $options = new Config();
+        $options->protocol = 'https';
+        $options->gatewayHost = 'openapi.alipay.com';
+        $options->signType = 'RSA2';
+
+        $options->appId = '2021002141666136';
+
+        // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
+        $options->merchantPrivateKey = 'MIIEpQIBAAKCAQEAhAunpRNIX2PaDe3wdTtMaWtUOGYBRUHBUTDdrwPbhJf7wd76EfUh6T/C6N+PcMjvsN6BJpMy/PqiP9aLKaY6W0oXaTILmTNk6v/Qdn+hLcrLhzN3sd+X9mZCcilc7o3/AKZkupcM2BguDoGugpdrhALmoRe20gDC0+0mLBTzBaA3VXxkPn9DXhl+ggsM7jy6SyMRwbC5EaQALnbtlitYhbdaZmloR5fDIsVkt2xPAHoJMG8nuTOEc213BxV/aS23ek6mwCUmZLvRvZvu/ODyHw1jhCRRzmPSI6ANezr8odY++ZTxzv6qHukKFCLF7RlzaNRzKgE8QfQ4yEO2EFPg1wIDAQABAoIBABC0dMICfX5r4HMwreH23YTcqiv0Y6bCWdWOrAzvHP9aRuRQ9Cv/agnbIipZ1gi7su8aRxZ9Os8cWhhfaP2c5PcVmX6acTMxeEvujw3euaJUbIkvLq5XDh+C8lcE+pfHaQJJCqc8YsiXzoPRTiWBSH3L7CdnG57Xr84ly1V6VQBaBPSq+QhjD4r8P1tucszKsflicR4RxauyQjJqsv19xY8poogw+rMX4eZvD4D50KbQewAAF6MOzHMeY+NQdTs65qevmYdULc54xEVrfvKxElcS/bB+1vbVolEKbxnK1d6676xVdHK8wGS/z5x4lRbdkntNgE2CrFZFY+ZuKpVKu2kCgYEAwGgXJXVF+79FcL4P/490QFxonaWT9IH2Jb7RYS6UdejReDhFjcp21HVPO0t+/0Ei82ihCxwckvpkJvvhDtST6IdH/tXNnuAjZzIqwtdfHzvjP2a2jjQeYwf7R4YjLT5ZA+2fOaVhXIR50yVPb+yj7XUnqgoLwhHKd0MBxL4tZeMCgYEAr7BK2tOYccQSgc+I3MslRLqwIAwXN89hV/3OkjwHjaRNbEw6rMIHHpa03+cVvaZLgxHYT/ULWUiIpguAwCD+aKLcoDqxSMGPOQsYHLuxCJPkvLlm/OOlpEHQrQB9ENSBI7nybBtfwvNiY7n9P9lpCczFSH3TRTxt/Q6AzrmEK30CgYEAo8+7bSvUYoqtX1iiHE4Rhr5mX1nahwCjBe3ZK+lRgrWuqbEXHqoy053w0CXtwPq+/AennOLZPRWrcTlfmpXIO9/5nvB++PYRjkm6+FoPZXNCffdAFAAxotTnzjRY/KspdFu6BYVVSESNyAPrBvqtcn0dQPr+mcM14qYM+mmEE0sCgYEAmIxhorpBzt6qFy7lrplxpcjYLytwaZRW+Lk3yX/4KwOz+koCVIkw911ydkvHc+HWBVvUUDD8hqzVgh/QzoKXhLGNEk+EKiFvQ9+fMyvB3ynTXg86HnFoHUTMdbtL3PY3n5bQqQ/nyXXdQ6x1+h/D9a9oybX/YUnEUwtpypYI7l0CgYEAjhsEOG9HHyUt/s3l5uSTo8EI4R3SPNE3d4V02Cm+nrCX40jO+TnkWcLuxdWXP2OUfd10chcIczjH1AtoRWbF/DLFBdYvBtS0N6JEdTD0UCYK/WH169hrXc247ycXGba6gPK2xq7oM3Zcso60+ibB+HEtTsrePTZlVDRNwsLmCnc=';
+
+        /*$options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
+        $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
+        $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';*/
+
+        //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
+        $options->alipayPublicKey ='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn/i44o8b1xAA8M026tGsl4gagl8Otx0r4pC69KP3dsaL2i7OS2a3lP9mLpQ/S1awqflc8TWGeLqxffUy/L4aF2zYuq17jeuwxfN0uc+8cxX8QvwhGUuWVt/u1MgdLjij5OOk1dgEy6s0EIhefFpOKX9WGSwOqa9rbstqt7grTJXexEIJ+gBvsQ/Vem32wwZMrzSsb7NNwuXMl+/j2RAf1zhnrvZUKQfdiSYuXtWYnLM2MJS258sMC0+q2ImKwhl5Oibt05xaFpL+gBBkyT3Jr+tkU3pcJXraoyhtXnCD0dNTTdr0xpLZsIEzEwoLgeX4XCa7iF3hQArgmmG3kAUNSQIDAQAB';
+        //可设置异步通知接收服务地址(可选)
+        $options->notifyUrl = $notifyUrl;
+        //可设置AES密钥,调用AES加解密相关接口时需要(可选)
+        $options->encryptKey = "";
+        return $options;
+    }
+    public static function getOptions_test($notifyUrl){
+        $options = new Config();
+        $options->protocol = 'https';
+        $options->gatewayHost = 'openapi.alipay.com';
+        $options->signType = 'RSA2';
+
+        $options->appId = '2021002142672998';
+
+        // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
+        $options->merchantPrivateKey = 'MIIEogIBAAKCAQEA2D4+Ps22cufmzn+mt14TOKNS0xHH+BX/2OpUM8RZh8YjMWqQyY4UlxDJeiegabOk2yRID3N4R2YlL6Ye51+3NxNTf3dCGe9ZllpaZJle0hS6KpRrX3d32HoadzQNQU2MjHN+G/OvoA7WuvfomdnY7OGDsxw++EWOcgueL62uEFAzMMsOxnoUBaf+MIXCW8bTl34dyj/5WiruVyUFVyfqh5RjFBm34UTW0d8OqV8eZfK1hr5ElzVrs3JbS8FCACQHznozJcWRH8GNjYVjOsJk2g30fTx4DmbTx3HWnfzFjrvy7Bp41XUeLmFpgTETRCMEE/Omq0DJCJ0Vi6uffJXSIQIDAQABAoIBAD9jR4XLcX8PYYYIv0sjJYlFvwKmRLMBZ+UjE5m1JfV57FkQ/u5GWtzJi/Xl5cz2Xw3p/cGhvJFZbO8hyA9U7HUVkjVcNSE7G0zKoZK5rqTwdH4E0dDDSXtIl7d3p6cL33ZQaJgy/7lwgBuAjkuDI2aU2LFJR2Apq47cvvsE83BOOBZu8fMPn8bMN+9sn+MGU0j71TZHwxOoV35aGrrikGVR0rNWc3ZJ+N0hVUH0jWV9C6av1dRPdXmH2wY1sB1LTDUqrxHde6jTPvPjGYOP1SQQZltXGzt9gZUPhKqjMuJNFZmRdi+uXfotE7U0RJAli/whZo3fOTNagFY+kkhZewECgYEA9NzgMahU/7QV34zBYxaiSVX0VE03RKtNTXjFUrklEXoQgvIlX8B2uyLIXOA47NGeUYL5lzuv0s+v5kelJX1OVZMmXm8zvRUtnI4a9iMXJpXIKx6i0frgjrPhYi1J0H6sf59fDTXi2qo6MuQyAwLjuIyl0w7gOpqRtSE48tMtnpECgYEA4hQgezNPzcDhYm6rh2YARtZRbhlpU1+LrF9wRhfHBmo+6i2V9gO1ljnHp5MMpMQmUmbWnrlUuK9YYIwCVcxp7LLfrlPs6nAN6htHcNrVHdVUNnUI1KsUxh1siEsfVAdAowl5+y3efcTZRdqnmMH/qb7ajNkGgBVuuU02bAUT4pECgYAJ8xutCOEDTucAoXCOPTI09qgp8MVJJgjLGBg0h09pSWN4XqyEGob4ja5Ej9vgS5g6Sa8opQU89LF6Evkz78aKFaOefLhGe6DR1rhjvgNHzxhGIEWPcLlFMyv6WErCjRMnUGuFVuYz6mzY+orJsolcS2LFk7oqx3MaQBJXU5tr8QKBgFTfD26QzcXFQhdsypIS9cmiDYHSolq9RLcaQRDfPkUnP6U0Jdbsf4/88vny101HocdPegSuOKL4mKnuBbZl/eHxKM3ODePY2zBmu0Qfst/3RR0IhJ8p9quFQkhMQ1+NNXO/S/7CsoLukk6KDl7nfW4hCvTTSIBvC1kfJm4Y3eUxAoGAB1FUyyZuSS5EQIRWmFktbGCGiAGBxu71yq2Fqmal/ggPGLLWFM3Gy4ISkTjbxshQzCvDxJOyDLl8+96NeTFjRb7CC2yoCgDUNe5/z7YgNlHggx5SKWcw3tqxDc1maMvp6tkNEX/VC6ePidxrEL4fM8jb+VFLXv1B1W4Ekr9fmJw=';
+
+        /*$options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->';
+        $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->';
+        $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->';*/
+
+        //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
+        $options->alipayPublicKey ='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn/i44o8b1xAA8M026tGsl4gagl8Otx0r4pC69KP3dsaL2i7OS2a3lP9mLpQ/S1awqflc8TWGeLqxffUy/L4aF2zYuq17jeuwxfN0uc+8cxX8QvwhGUuWVt/u1MgdLjij5OOk1dgEy6s0EIhefFpOKX9WGSwOqa9rbstqt7grTJXexEIJ+gBvsQ/Vem32wwZMrzSsb7NNwuXMl+/j2RAf1zhnrvZUKQfdiSYuXtWYnLM2MJS258sMC0+q2ImKwhl5Oibt05xaFpL+gBBkyT3Jr+tkU3pcJXraoyhtXnCD0dNTTdr0xpLZsIEzEwoLgeX4XCa7iF3hQArgmmG3kAUNSQIDAQAB';
+        //可设置异步通知接收服务地址(可选)
+        $options->notifyUrl = $notifyUrl;
+        //可设置AES密钥,调用AES加解密相关接口时需要(可选)
+        $options->encryptKey = "";
+        return $options;
+    }
+
+    //保证金支付回调
+    public function deposit_notify()
+    {
+        $result = input('post.');
+        if ($result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED') {
+            $pay_no = $result['out_trade_no'];
+
+            // 用户支付成功处理
+            $order_info = Db::name('store_deposit_order')->where('pay_no',$pay_no)->where('status',0)->find();
+            if(empty($order_info)){
+                return false;
+            }
+            Db::table('store_deposit_order')->where('pay_no',$order_info['pay_no'])->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
+            $wid = Db::table('store_deposit_order')->where('pay_no',$order_info['pay_no'])->value('worker_id');
+            //更新是否缴纳保证金
+            Db::name('store_worker')->where('id',$wid)->update(array('deposit'=>1));
+            //添加运输路线
+            $county_arr = explode(',',$order_info['county']);
+            foreach ($county_arr as $area){
+                $city_id = Db::name('store_area')->where('id',$area)->value('pid');
+                $province_id = Db::name('store_area')->where('id',$city_id)->value('pid');
+                $area_data = array(
+                    'worker_id' => $wid,
+                    'start_province_id' => $order_info['start_province'],
+                    'start_city_id' => $order_info['start_city'],
+                    'start_county_id' => $order_info['start_county'],
+                    'end_province_id' => $province_id,
+                    'end_city_id' => $city_id,
+                    'end_county_id' => $area
+                );
+                Db::name('store_serve_area')->insert($area_data);
+            }
+            return true; // 返回处理完成
+        } else {
+
+        }
+    }
+    //自动报价支付回调
+    public function offer_notify()
+    {
+        $result = input('post.');
+        if ($result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED') {
+            $pay_no = $result['out_trade_no'];
+            // 用户支付成功处理
+            $order_info = Db::name('store_offer_order')->where('pay_no',$pay_no)->where('status',0)->find();
+            if(empty($order_info)){
+                return false;
+            }
+            Db::table('store_offer_order')->where('pay_no',$pay_no)->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
+            $order_info = Db::table('store_offer_order')->where('pay_no',$pay_no)->find();
+            //添加接单人员自动报价信息
+            $offer_time = Db::name('store_worker')->where('id',$order_info['worker_id'])->value('offer_time');
+            $offer_timestamp = 0;
+            if($order_info['type'] == 1){
+                $offer_timestamp = strtotime('next month');
+            }elseif($order_info['type'] == 2){
+                $offer_timestamp = strtotime('+3 month');
+            }elseif ($order_info['type'] == 3){
+                $offer_timestamp = strtotime('+1years');
+            }
+            if($offer_time && $offer_time > time()){
+                $offer_timestamp = $offer_timestamp + ($offer_time - time());
+            }
+            Db::name('store_worker')->where('id',$order_info['worker_id'])->update(array('offer_time'=>$offer_timestamp));
+            return true; // 返回处理完成
+        } else {
+
+        }
+    }
+    //PC端雇主下单支付回调
+    public function order_notify()
+    {
+        $result = input('post.');
+        if ($result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED') {
+            $pay_no = $result['out_trade_no'];
+
+            // 用户支付成功处理
+            $order_info = Db::name('store_order')->where('pay_no',$pay_no)->where('status',1)->find();
+            if(empty($order_info)){
+                return false;
+            }
+            // 用户支付成功处理
+            $order_info = Db::name('store_order')->field('id,worker_id')->where('pay_no',$pay_no)->find();
+            Db::startTrans();
+            $res = Db::table('store_order')->where('id',$order_info['id'])->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_status'=>1,'status'=>2]);
+            $error = 0;
+            if(!$res){
+                $error = 1;
+                Db::rollback();
+            }
+            $pay_obj = new Pay();
+            if($order_info['worker_id']) {
+                $rebate_res = $pay_obj->serve_rebate($order_info['id']);
+                if (!$rebate_res['code']) {
+                    $error = 2;
+                    Db::rollback();
+                }
+            }
+            if($error == 0){
+                Db::commit();
+            }
+            return true; // 返回处理完成
+        } else {
+
+        }
+    }
+    //PC端充值余额支付
+    public function balance_notify()
+    {
+        $result = input('post.');
+        if ($result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED') {
+            $pay_no = $result['out_trade_no'];
+
+            // 用户支付成功处理
+            $order_info = Db::name('store_balance_order')->where('pay_no',$pay_no)->where('status',0)->find();
+            if(empty($order_info)){
+                return false;
+            }
+            // 用户支付成功处理
+            $order_info = Db::name('store_balance_order')->where('pay_no',$pay_no)->find();
+            Db::startTrans();
+            $res = Db::table('store_balance_order')->where('user_id',$order_info['user_id'])->where('pay_no',$order_info['pay_no'])->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
+            $error = 0;
+            if(!$res){
+                $error = 1;
+                Db::rollback();
+            }
+            $balance_data = array(
+                'amount' => $order_info['price_total'],
+                'user_id' => $order_info['user_id'],
+                'order_id' => $order_info['id'],
+                'status' => 1
+            );
+            $balance_list = Db::name('store_balance_list')->insert($balance_data);
+            if(!$balance_list){
+                $error = 2;
+                Db::rollback();
+            }
+            $member_balance = Db::name('store_member')->where('id',$order_info['user_id'])->setInc('balance',$order_info['price_total']);
+            if(!$member_balance){
+                $error = 3;
+                Db::rollback();
+            }
+            $member_balance_all = Db::name('store_member')->where('id',$order_info['user_id'])->setInc('balance_all',$order_info['price_total']);
+            if(!$member_balance_all){
+                $error = 4;
+                Db::rollback();
+            }
+            if($error == 0){
+                Db::commit();
+            }
+            return true; // 返回处理完成
+        } else {
+
+        }
+    }
+    //PC雇主端增加费用
+    public function expenses_order_notify()
+    {
+        $result = input('post.');
+        if ($result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED') {
+            $pay_no = $result['out_trade_no'];
+
+            // 用户支付成功处理
+            $order_info = Db::name('store_expenses_order')->where('pay_no',$pay_no)->where('status',0)->find();
+            if(empty($order_info)){
+                return false;
+            }
+            // 用户支付成功处理
+            $order_info = Db::name('store_expenses_order')->field('id,order_id,price_total,reason')->where('pay_no',$pay_no)->find();
+            // 用户支付成功处理
+            Db::startTrans();
+            $expenses_order_res = Db::table('store_expenses_order')->where('id',$order_info['id'])->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
+            $error = 0;
+            if(!$expenses_order_res){
+                $error = 1;
+                Db::rollback();
+            }
+            $pay_obj = new Pay();
+            $rebate_res = $pay_obj->add_serve_rebate($order_info['id']);
+            if(!$rebate_res){
+                $error = 2;
+                Db::rollback();
+            }
+            $store_order_info = Db::name('store_order')->field('price_total,price_amount')->where('id',$order_info['order_id'])->find();
+            $store_order_res = Db::name('store_order')->where('id',$order_info['order_id'])->update(['expenses_time'=>date('Y-m-d H:i:s'),'expenses_pay_type'=>1,'expenses_amount'=>$order_info['price_total'],'expenses_reason'=>$order_info['reason'],'price_total'=>$store_order_info['price_total'] + $order_info['price_total'],'price_amount'=>$store_order_info['price_amount'] + $order_info['price_total']]);
+            if(!$store_order_res){
+                $error = 3;
+                Db::rollback();
+            }
+            if($error == 0){
+                Db::commit();
+            }else{
+                Db::rollback();
+            }
+            return true; // 返回处理完成
+        } else {
+
+        }
+    }
+}

+ 865 - 0
application/api/controller/ApiRedis.php

@@ -0,0 +1,865 @@
+<?php
+namespace app\api\controller;
+/**
+ * redis操作类
+ * 说明,任何为false的串,存在redis中都是空串。
+ * 只有在key不存在时,才会返回false。
+ * 这点可用于防止缓存穿透
+ *
+ */
+use think\cache\driver\Redis;
+class ApiRedis
+{
+    private $redis;
+    //当前数据库ID号
+    protected $dbId=0;
+    //当前权限认证码
+    protected $auth;
+    /**
+     * 实例化的对象,单例模式.
+     * @var \iphp\db\Redis
+     */
+    static private $_instance=array();
+    private $k;
+    //连接属性数组
+    protected $attr=array(
+        //连接超时时间,redis配置文件中默认为300秒
+        'timeout'=>300,
+        //选择的数据库。
+        'db_id'=>0,
+    );
+    //什么时候重新建立连接
+    protected $expireTime;
+    protected $host;
+    protected $port;
+    private function __construct($config,$attr=array())
+    {
+        $this->attr    =  array_merge($this->attr,$attr);
+        $this->redis  =  new Redis();
+        $this->port    =  $config['port'] ? $config['port'] : 6379;
+        $this->host    =  $config['host'];
+        $this->redis->connect($this->host, $this->port, $this->attr['timeout']);
+        if($config['auth'])
+        {
+            $this->auth($config['auth']);
+            $this->auth  =  $config['auth'];
+        }
+        $this->expireTime  =  time() + $this->attr['timeout'];
+    }
+    /**
+     * 得到实例化的对象.
+     * 为每个数据库建立一个连接
+     * 如果连接超时,将会重新建立一个连接
+     * @param array $config
+     * @param int $dbId
+     * @return \iphp\db\Redis
+     */
+    public static function getInstance($config, $attr = array())
+    {
+        //如果是一个字符串,将其认为是数据库的ID号。以简化写法。
+        if(!is_array($attr))
+        {
+            $dbId  =  $attr;
+            $attr  =  array();
+            $attr['db_id']  =  $dbId;
+        }
+        $attr['db_id']  =  $attr['db_id'] ? $attr['db_id'] : 0;
+        $k  =  md5(implode('', $config).$attr['db_id']);
+        if(! (static::$_instance[$k] instanceof self))
+        {
+            static::$_instance[$k] = new self($config,$attr);
+            static::$_instance[$k]->k    =  $k;
+            static::$_instance[$k]->dbId  =  $attr['db_id'];
+            //如果不是0号库,选择一下数据库。
+            if($attr['db_id'] != 0){
+                static::$_instance[$k]->select($attr['db_id']);
+            }
+        }
+        elseif( time() > static::$_instance[$k]->expireTime)
+        {
+            static::$_instance[$k]->close();
+            static::$_instance[$k]     =   new self($config,$attr);
+            static::$_instance[$k]->k  =  $k;
+            static::$_instance[$k]->dbId=  $attr['db_id'];
+            //如果不是0号库,选择一下数据库。
+            if($attr['db_id']!=0){
+                static::$_instance[$k]->select($attr['db_id']);
+            }
+        }
+        return static::$_instance[$k];
+    }
+    private function __clone(){}
+    /**
+     * 执行原生的redis操作
+     * @return \Redis
+     */
+    public function getRedis()
+    {
+        return $this->redis;
+    }
+    /*****************hash表操作函数*******************/
+    /**
+     * 得到hash表中一个字段的值
+     * @param string $key 缓存key
+     * @param string $field 字段
+     * @return string|false
+     */
+    public function hGet($key,$field)
+    {
+        return $this->redis->hGet($key,$field);
+    }
+    /**
+     * 为hash表设定一个字段的值
+     * @param string $key 缓存key
+     * @param string $field 字段
+     * @param string $value 值。
+     * @return bool
+     */
+    public function hSet($key,$field,$value)
+    {
+        return $this->redis->hSet($key,$field,$value);
+    }
+    /**
+     * 判断hash表中,指定field是不是存在
+     * @param string $key 缓存key
+     * @param string $field 字段
+     * @return bool
+     */
+    public function hExists($key,$field)
+    {
+        return $this->redis->hExists($key,$field);
+    }
+    /**
+     * 删除hash表中指定字段 ,支持批量删除
+     * @param string $key 缓存key
+     * @param string $field 字段
+     * @return int
+     */
+    public function hdel($key,$field)
+    {
+        $fieldArr=explode(',',$field);
+        $delNum=0;
+        foreach($fieldArr as $row)
+        {
+            $row=trim($row);
+            $delNum+=$this->redis->hDel($key,$row);
+        }
+        return $delNum;
+    }
+    /**
+     * 返回hash表元素个数
+     * @param string $key 缓存key
+     * @return int|bool
+     */
+    public function hLen($key)
+    {
+        return $this->redis->hLen($key);
+    }
+    /**
+     * 为hash表设定一个字段的值,如果字段存在,返回false
+     * @param string $key 缓存key
+     * @param string $field 字段
+     * @param string $value 值。
+     * @return bool
+     */
+    public function hSetNx($key,$field,$value)
+    {
+        return $this->redis->hSetNx($key,$field,$value);
+    }
+    /**
+     * 为hash表多个字段设定值。
+     * @param string $key
+     * @param array $value
+     * @return array|bool
+     */
+    public function hMset($key,$value)
+    {
+        if(!is_array($value))
+            return false;
+        return $this->redis->hMset($key,$value);
+    }
+    /**
+     * 为hash表多个字段设定值。
+     * @param string $key
+     * @param array|string $value string以','号分隔字段
+     * @return array|bool
+     */
+    public function hMget($key,$field)
+    {
+        if(!is_array($field))
+            $field=explode(',', $field);
+        return $this->redis->hMget($key,$field);
+    }
+    /**
+     * 为hash表设这累加,可以负数
+     * @param string $key
+     * @param int $field
+     * @param string $value
+     * @return bool
+     */
+    public function hIncrBy($key,$field,$value)
+    {
+        $value=intval($value);
+        return $this->redis->hIncrBy($key,$field,$value);
+    }
+    /**
+     * 返回所有hash表的所有字段
+     * @param string $key
+     * @return array|bool
+     */
+    public function hKeys($key)
+    {
+        return $this->redis->hKeys($key);
+    }
+    /**
+     * 返回所有hash表的字段值,为一个索引数组
+     * @param string $key
+     * @return array|bool
+     */
+    public function hVals($key)
+    {
+        return $this->redis->hVals($key);
+    }
+    /**
+     * 返回所有hash表的字段值,为一个关联数组
+     * @param string $key
+     * @return array|bool
+     */
+    public function hGetAll($key)
+    {
+        return $this->redis->hGetAll($key);
+    }
+    /*********************有序集合操作*********************/
+    /**
+     * 给当前集合添加一个元素
+     * 如果value已经存在,会更新order的值。
+     * @param string $key
+     * @param string $order 序号
+     * @param string $value 值
+     * @return bool
+     */
+    public function zAdd($key,$order,$value)
+    {
+        return $this->redis->zAdd($key,$order,$value);
+    }
+    /**
+     * 给$value成员的order值,增加$num,可以为负数
+     * @param string $key
+     * @param string $num 序号
+     * @param string $value 值
+     * @return 返回新的order
+     */
+    public function zinCry($key,$num,$value)
+    {
+        return $this->redis->zinCry($key,$num,$value);
+    }
+    /**
+     * 删除值为value的元素
+     * @param string $key
+     * @param stirng $value
+     * @return bool
+     */
+    public function zRem($key,$value)
+    {
+        return $this->redis->zRem($key,$value);
+    }
+    /**
+     * 集合以order递增排列后,0表示第一个元素,-1表示最后一个元素
+     * @param string $key
+     * @param int $start
+     * @param int $end
+     * @return array|bool
+     */
+    public function zRange($key,$start,$end)
+    {
+        return $this->redis->zRange($key,$start,$end);
+    }
+    /**
+     * 集合以order递减排列后,0表示第一个元素,-1表示最后一个元素
+     * @param string $key
+     * @param int $start
+     * @param int $end
+     * @return array|bool
+     */
+    public function zRevRange($key,$start,$end)
+    {
+        return $this->redis->zRevRange($key,$start,$end);
+    }
+    /**
+     * 集合以order递增排列后,返回指定order之间的元素。
+     * min和max可以是-inf和+inf 表示最大值,最小值
+     * @param string $key
+     * @param int $start
+     * @param int $end
+     * @package array $option 参数
+     *   withscores=>true,表示数组下标为Order值,默认返回索引数组
+     *   limit=>array(0,1) 表示从0开始,取一条记录。
+     * @return array|bool
+     */
+    public function zRangeByScore($key,$start='-inf',$end="+inf",$option=array())
+    {
+        return $this->redis->zRangeByScore($key,$start,$end,$option);
+    }
+    /**
+     * 集合以order递减排列后,返回指定order之间的元素。
+     * min和max可以是-inf和+inf 表示最大值,最小值
+     * @param string $key
+     * @param int $start
+     * @param int $end
+     * @package array $option 参数
+     *   withscores=>true,表示数组下标为Order值,默认返回索引数组
+     *   limit=>array(0,1) 表示从0开始,取一条记录。
+     * @return array|bool
+     */
+    public function zRevRangeByScore($key,$start='-inf',$end="+inf",$option=array())
+    {
+        return $this->redis->zRevRangeByScore($key,$start,$end,$option);
+    }
+    /**
+     * 返回order值在start end之间的数量
+     * @param unknown $key
+     * @param unknown $start
+     * @param unknown $end
+     */
+    public function zCount($key,$start,$end)
+    {
+        return $this->redis->zCount($key,$start,$end);
+    }
+    /**
+     * 返回值为value的order值
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function zScore($key,$value)
+    {
+        return $this->redis->zScore($key,$value);
+    }
+    /**
+     * 返回集合以score递增加排序后,指定成员的排序号,从0开始。
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function zRank($key,$value)
+    {
+        return $this->redis->zRank($key,$value);
+    }
+    /**
+     * 返回集合以score递增加排序后,指定成员的排序号,从0开始。
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function zRevRank($key,$value)
+    {
+        return $this->redis->zRevRank($key,$value);
+    }
+    /**
+     * 删除集合中,score值在start end之间的元素 包括start end
+     * min和max可以是-inf和+inf 表示最大值,最小值
+     * @param unknown $key
+     * @param unknown $start
+     * @param unknown $end
+     * @return 删除成员的数量。
+     */
+    public function zRemRangeByScore($key,$start,$end)
+    {
+        return $this->redis->zRemRangeByScore($key,$start,$end);
+    }
+    /**
+     * 返回集合元素个数。
+     * @param unknown $key
+     */
+    public function zCard($key)
+    {
+        return $this->redis->zCard($key);
+    }
+    /*********************队列操作命令************************/
+    /**
+     * 在队列尾部插入一个元素
+     * @param unknown $key
+     * @param unknown $value
+     * 返回队列长度
+     */
+    public function rPush($key,$value)
+    {
+        return $this->redis->rPush($key,$value);
+    }
+    /**
+     * 在队列尾部插入一个元素 如果key不存在,什么也不做
+     * @param unknown $key
+     * @param unknown $value
+     * 返回队列长度
+     */
+    public function rPushx($key,$value)
+    {
+        return $this->redis->rPushx($key,$value);
+    }
+    /**
+     * 在队列头部插入一个元素
+     * @param unknown $key
+     * @param unknown $value
+     * 返回队列长度
+     */
+    public function lPush($key,$value)
+    {
+        return $this->redis->lPush($key,$value);
+    }
+    /**
+     * 在队列头插入一个元素 如果key不存在,什么也不做
+     * @param unknown $key
+     * @param unknown $value
+     * 返回队列长度
+     */
+    public function lPushx($key,$value)
+    {
+        return $this->redis->lPushx($key,$value);
+    }
+    /**
+     * 返回队列长度
+     * @param unknown $key
+     */
+    public function lLen($key)
+    {
+        return $this->redis->lLen($key);
+    }
+    /**
+     * 返回队列指定区间的元素
+     * @param unknown $key
+     * @param unknown $start
+     * @param unknown $end
+     */
+    public function lRange($key,$start,$end)
+    {
+        return $this->redis->lrange($key,$start,$end);
+    }
+    /**
+     * 返回队列中指定索引的元素
+     * @param unknown $key
+     * @param unknown $index
+     */
+    public function lIndex($key,$index)
+    {
+        return $this->redis->lIndex($key,$index);
+    }
+    /**
+     * 设定队列中指定index的值。
+     * @param unknown $key
+     * @param unknown $index
+     * @param unknown $value
+     */
+    public function lSet($key,$index,$value)
+    {
+        return $this->redis->lSet($key,$index,$value);
+    }
+    /**
+     * 删除值为vaule的count个元素
+     * PHP-REDIS扩展的数据顺序与命令的顺序不太一样,不知道是不是bug
+     * count>0 从尾部开始
+     * >0 从头部开始
+     * =0 删除全部
+     * @param unknown $key
+     * @param unknown $count
+     * @param unknown $value
+     */
+    public function lRem($key,$count,$value)
+    {
+        return $this->redis->lRem($key,$value,$count);
+    }
+    /**
+     * 删除并返回队列中的头元素。
+     * @param unknown $key
+     */
+    public function lPop($key)
+    {
+        return $this->redis->lPop($key);
+    }
+    /**
+     * 删除并返回队列中的尾元素
+     * @param unknown $key
+     */
+    public function rPop($key)
+    {
+        return $this->redis->rPop($key);
+    }
+    /*************redis字符串操作命令*****************/
+    /**
+     * 设置一个key
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function set($key,$value)
+    {
+        return $this->redis->set($key,$value);
+    }
+    /**
+     * 得到一个key
+     * @param unknown $key
+     */
+    public function get($key)
+    {
+        return $this->redis->get($key);
+    }
+    /**
+     * 设置一个有过期时间的key
+     * @param unknown $key
+     * @param unknown $expire
+     * @param unknown $value
+     */
+    public function setex($key,$expire,$value)
+    {
+        return $this->redis->setex($key,$expire,$value);
+    }
+    /**
+     * 设置一个key,如果key存在,不做任何操作.
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function setnx($key,$value)
+    {
+        return $this->redis->setnx($key,$value);
+    }
+    /**
+     * 批量设置key
+     * @param unknown $arr
+     */
+    public function mset($arr)
+    {
+        return $this->redis->mset($arr);
+    }
+    /*************redis 无序集合操作命令*****************/
+    /**
+     * 返回集合中所有元素
+     * @param unknown $key
+     */
+    public function sMembers($key)
+    {
+        return $this->redis->sMembers($key);
+    }
+    /**
+     * 求2个集合的差集
+     * @param unknown $key1
+     * @param unknown $key2
+     */
+    public function sDiff($key1,$key2)
+    {
+        return $this->redis->sDiff($key1,$key2);
+    }
+    /**
+     * 添加集合。由于版本问题,扩展不支持批量添加。这里做了封装
+     * @param unknown $key
+     * @param string|array $value
+     */
+    public function sAdd($key,$value)
+    {
+        if(!is_array($value))
+            $arr=array($value);
+        else
+            $arr=$value;
+        foreach($arr as $row)
+            $this->redis->sAdd($key,$row);
+    }
+    /**
+     * 返回无序集合的元素个数
+     * @param unknown $key
+     */
+    public function scard($key)
+    {
+        return $this->redis->scard($key);
+    }
+    /**
+     * 从集合中删除一个元素
+     * @param unknown $key
+     * @param unknown $value
+     */
+    public function srem($key,$value)
+    {
+        return $this->redis->srem($key,$value);
+    }
+    /*************redis管理操作命令*****************/
+    /**
+     * 选择数据库
+     * @param int $dbId 数据库ID号
+     * @return bool
+     */
+    public function select($dbId)
+    {
+        $this->dbId=$dbId;
+        return $this->redis->select($dbId);
+    }
+    /**
+     * 清空当前数据库
+     * @return bool
+     */
+    public function flushDB()
+    {
+        return $this->redis->flushDB();
+    }
+    /**
+     * 返回当前库状态
+     * @return array
+     */
+    public function info()
+    {
+        return $this->redis->info();
+    }
+    /**
+     * 同步保存数据到磁盘
+     */
+    public function save()
+    {
+        return $this->redis->save();
+    }
+    /**
+     * 异步保存数据到磁盘
+     */
+    public function bgSave()
+    {
+        return $this->redis->bgSave();
+    }
+    /**
+     * 返回最后保存到磁盘的时间
+     */
+    public function lastSave()
+    {
+        return $this->redis->lastSave();
+    }
+    /**
+     * 返回key,支持*多个字符,?一个字符
+     * 只有* 表示全部
+     * @param string $key
+     * @return array
+     */
+    public function keys($key)
+    {
+        return $this->redis->keys($key);
+    }
+    /**
+     * 删除指定key
+     * @param unknown $key
+     */
+    public function del($key)
+    {
+        return $this->redis->del($key);
+    }
+    /**
+     * 判断一个key值是不是存在
+     * @param unknown $key
+     */
+    public function exists($key)
+    {
+        return $this->redis->exists($key);
+    }
+    /**
+     * 为一个key设定过期时间 单位为秒
+     * @param unknown $key
+     * @param unknown $expire
+     */
+    public function expire($key,$expire)
+    {
+        return $this->redis->expire($key,$expire);
+    }
+    /**
+     * 返回一个key还有多久过期,单位秒
+     * @param unknown $key
+     */
+    public function ttl($key)
+    {
+        return $this->redis->ttl($key);
+    }
+    /**
+     * 设定一个key什么时候过期,time为一个时间戳
+     * @param unknown $key
+     * @param unknown $time
+     */
+    public function exprieAt($key,$time)
+    {
+        return $this->redis->expireAt($key,$time);
+    }
+    /**
+     * 关闭服务器链接
+     */
+    public function close()
+    {
+        return $this->redis->close();
+    }
+    /**
+     * 关闭所有连接
+     */
+    public static function closeAll()
+    {
+        foreach(static::$_instance as $o)
+        {
+            if($o instanceof self)
+                $o->close();
+        }
+    }
+    /** 这里不关闭连接,因为session写入会在所有对象销毁之后。
+    public function __destruct()
+    {
+    return $this->redis->close();
+    }
+     **/
+    /**
+     * 返回当前数据库key数量
+     */
+    public function dbSize()
+    {
+        return $this->redis->dbSize();
+    }
+    /**
+     * 返回一个随机key
+     */
+    public function randomKey()
+    {
+        return $this->redis->randomKey();
+    }
+    /**
+     * 得到当前数据库ID
+     * @return int
+     */
+    public function getDbId()
+    {
+        return $this->dbId;
+    }
+    /**
+     * 返回当前密码
+     */
+    public function getAuth()
+    {
+        return $this->auth;
+    }
+    public function getHost()
+    {
+        return $this->host;
+    }
+    public function getPort()
+    {
+        return $this->port;
+    }
+    public function getConnInfo()
+    {
+        return array(
+            'host'=>$this->host,
+            'port'=>$this->port,
+            'auth'=>$this->auth
+        );
+    }
+    /*********************事务的相关方法************************/
+    /**
+     * 监控key,就是一个或多个key添加一个乐观锁
+     * 在此期间如果key的值如果发生的改变,刚不能为key设定值
+     * 可以重新取得Key的值。
+     * @param unknown $key
+     */
+    public function watch($key)
+    {
+        return $this->redis->watch($key);
+    }
+    /**
+     * 取消当前链接对所有key的watch
+     * EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了
+     */
+    public function unwatch()
+    {
+        return $this->redis->unwatch();
+    }
+    /**
+     * 开启一个事务
+     * 事务的调用有两种模式Redis::MULTI和Redis::PIPELINE,
+     * 默认是Redis::MULTI模式,
+     * Redis::PIPELINE管道模式速度更快,但没有任何保证原子性有可能造成数据的丢失
+     */
+    public function multi($type=\Redis::MULTI)
+    {
+        return $this->redis->multi($type);
+    }
+    /**
+     * 执行一个事务
+     * 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
+     */
+    public function exec()
+    {
+        return $this->redis->exec();
+    }
+    /**
+     * 回滚一个事务
+     */
+    public function discard()
+    {
+        return $this->redis->discard();
+    }
+    /**
+     * 测试当前链接是不是已经失效
+     * 没有失效返回+PONG
+     * 失效返回false
+     */
+    public function ping()
+    {
+        return $this->redis->ping();
+    }
+    public function auth($auth)
+    {
+        return $this->redis->auth($auth);
+    }
+    /*********************自定义的方法,用于简化操作************************/
+    /**
+     * 得到一组的ID号
+     * @param unknown $prefix
+     * @param unknown $ids
+     */
+    public function hashAll($prefix,$ids)
+    {
+        if($ids==false)
+            return false;
+        if(is_string($ids))
+            $ids=explode(',', $ids);
+        $arr=array();
+        foreach($ids as $id)
+        {
+            $key=$prefix.'.'.$id;
+            $res=$this->hGetAll($key);
+            if($res!=false)
+                $arr[]=$res;
+        }
+        return $arr;
+    }
+    /**
+     * 生成一条消息,放在redis数据库中。使用0号库。
+     * @param string|array $msg
+     */
+    public function pushMessage($lkey,$msg)
+    {
+        if(is_array($msg)){
+            $msg  =  json_encode($msg);
+        }
+        $key  =  md5($msg);
+        //如果消息已经存在,删除旧消息,已当前消息为准
+        //echo $n=$this->lRem($lkey, 0, $key)."\n";
+        //重新设置新消息
+        $this->lPush($lkey, $key);
+        $this->setex($key, 3600, $msg);
+        return $key;
+    }
+    /**
+     * 得到条批量删除key的命令
+     * @param unknown $keys
+     * @param unknown $dbId
+     */
+    public function delKeys($keys,$dbId)
+    {
+        $redisInfo=$this->getConnInfo();
+        $cmdArr=array(
+            'redis-cli',
+            '-a',
+            $redisInfo['auth'],
+            '-h',
+            $redisInfo['host'],
+            '-p',
+            $redisInfo['port'],
+            '-n',
+            $dbId,
+        );
+        $redisStr=implode(' ', $cmdArr);
+        $cmd="{$redisStr} KEYS \"{$keys}\" | xargs {$redisStr} del";
+        return $cmd;
+    }
+}

+ 100 - 0
application/api/controller/Appointment.php

@@ -0,0 +1,100 @@
+<?php
+namespace app\api\controller;
+use app\common\model\NewsCate;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\UserAppointment;
+use app\common\model\UserCollect;
+use app\common\model\InformationArticle;
+use app\common\model\VideoCate;
+use app\common\model\VideoIntro;
+use app\common\model\GoodsCate;
+use think\Db;
+use library\tools\Data;
+/**
+ * @title 预约
+ * @controller Appointment
+ * @group base
+ */
+class Appointment extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+
+    /**
+     * @title 用户预约
+     * @desc 目前只有商品预约
+     * @author qc
+     * @method POST
+     * @url /api/Appointment/userAppointment
+     * @header name:Authorization require:1 desc:Token
+     * @param name:id type:int default:-- desc:商品id
+     */
+    public function userAppointment()
+    {
+        $app_id = input('post.id');
+        if(!$app_id) $this->error('参数错误');
+        $app_type = input('post.app_type',1);
+        $app_info = [
+            'user_id' =>$this->user_id,
+            'app_id' =>$app_id,
+            'app_type' =>$app_type,
+            'create_at' =>date('Y-m-d H:i:s'),
+        ];
+        Data::save('UserAppointment',$app_info,'user_id',[ 'user_id' =>$this->user_id, 'app_id' =>$app_id,'app_type' =>input('post.app_type',1)]);
+        $this->success('预约成功');
+    }
+
+
+    /**
+     * @title 获取预约记录
+     * @desc 获取预约记录
+     * @author qc
+     * @method GET
+     * @url /api/Appointment/user_info
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:视频id(不传查全部的视频商品)
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @return name:id type:int default:-- desc:预约记录id
+     * @return name:app_id type:int default:-- desc:预约商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:create_at type:string default:-- desc:时间
+     */
+    public function getUserAppointmentList()
+    {
+        $list = UserAppointment::field('a.id,a.app_id,a.create_at,g.name,g.cover')
+            ->alias('a')
+            ->leftJoin('StoreGoods g','g.id = a.app_id')
+            ->order('a.create_at desc ,a.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 取消预约
+     * @desc 取消预约
+     * @author qc
+     * @method POST
+     * @url /api/Appointment/cancelAppointment
+     * @header name:Authorization require:1 desc:Token
+     * @param name:ids type:string  : default:'' desc:需要删除的id记录(用逗号隔开)
+     */
+    public function cancelAppointment()
+    {
+        $ids = input('post.ids','');
+        if(!$ids) $this->error('请选择要取消预约的记录');
+        UserAppointment::where('id','in',$ids)->where('user_id','=',$this->user_id)->delete();
+        $this->success('取消成功');
+    }
+
+
+
+}

+ 120 - 0
application/api/controller/Area.php

@@ -0,0 +1,120 @@
+<?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\api\controller;
+use app\common\model\ChinaArea;
+use think\Db;
+/**
+ * @title 地址库
+ * @controller Area
+ * @group common
+ */
+class Area extends Base
+{
+
+    /**
+     * @title 获取地址库数据
+     * @desc 获取地址库数据
+     * @author qc
+     * @method GET
+     * @url /api/area/getAreaTree
+     * @header name:Authorization require:1 desc:Token
+     * @param name:level type:int require:0 default:0 desc:查询等级(0全部,1精确到省,2精确到市,3精确到县区,4精确到街道)
+     * @return name:name type:string default:-- desc:名称
+     * @return name:short_name type:string default:-- desc:简称
+     * @return name:level type:int default:-- desc:等级(1省,2市,3区,4道)
+     * @return name:code type:int default:-- desc:编码
+     * @return name:lng type:string default:-- desc:经度
+     * @return name:lat type:string default:-- desc:纬度
+     * @return name:children type:array default:-- desc:下级(数据字段同上)
+     */
+    public function getAreaTree()
+    {
+        $level = input('level');
+        if($level){
+            $all_area = ChinaArea::where('level','<=',$level)->select();
+        }else{
+            $all_area = ChinaArea::where('level','>',0)->order('level asc,sort desc,id asc')->select();
+        }
+        $this->success('ok',['list'=>make_tree($all_area)]);
+    }
+
+    /**
+     * @title 获取地址库ID获取下一级
+     * @desc 获取地址库ID获取下一级
+     * @author qc
+     * @method GET
+     * @url /api/area/getAreaChildrenByID
+     * @header name:Authorization require:1 desc:Token
+     * @param name:id type:int require:0 default:0 desc:数据表地址记录id
+     * @return name:name type:string default:-- desc:名称
+     * @return name:short_name type:string default:-- desc:简称
+     * @return name:level type:int default:-- desc:等级(1省,2市,3区,4道)
+     * @return name:code type:int default:-- desc:编码
+     * @return name:lng type:string default:-- desc:经度
+     * @return name:lat type:string default:-- desc:纬度
+     * @return name:children type:array default:-- desc:下级(数据字段同上)
+     */
+    public function getAreaChildrenByID()
+    {
+        $id = input('id');
+        $list = ChinaArea::where('pid',$id)->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取市级地址
+     * @desc 获取市级地址
+     * @author qc
+     * @method GET
+     * @url /api/area/getCityByName
+     * @header name:Authorization require:1 desc:Token
+     * @param name:name type:string require:0 default:0 desc:市名(或拼音)模糊查询(不传查全部)
+     * @return name:name type:string default:-- desc:名称
+     * @return name:short_name type:string default:-- desc:简称
+     */
+    public function getCityByName()
+    {
+        $where = [];
+        $where[] = ['level','=',2];
+        if(input('name'))   $where[] = ['name|pinyin','like','%'.input('name').'%'];
+        $all_city = ChinaArea::field('id,name,short_name,first')->where($where)->order('sort desc,id asc')->select();
+        $this->success('ok',['list'=>$all_city]);
+    }
+
+
+    /**
+     * @title 首字母分组获取地级市
+     * @desc 首字母分组获取地级市
+     * @author qc
+     * @method GET
+     * @url /api/area/getAllCity
+     * @header name:Authorization require:1 desc:Token
+     * @return name:first type:string default:-- desc:首字母
+     * @return name:city_list type:array default:-- desc:城市列表
+     * @return name:city_list.name type:string default:-- desc:名称
+     * @return name:city_list.short_name type:string default:-- desc:简称
+     */
+    public function getAllCity()
+    {
+       $list =  ChinaArea::getAllCity();
+       $this->success('ok',['list'=>$list]);
+    }
+
+
+
+
+
+}

+ 215 - 0
application/api/controller/Base.php

@@ -0,0 +1,215 @@
+<?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\api\controller;
+use Firebase\JWT\JWT;
+use think\Controller;
+use think\Db;
+use think\Exception;
+use think\exception\HttpResponseException;
+use think\Request;
+use think\Response;
+use function AlibabaCloud\Client\value;
+
+/**
+ * 会员管理基类
+ * Class Member
+ * @package app\store\controller\api
+ */
+class Base extends Controller
+{
+    protected $user_id = 0;
+    protected $page; // 页数
+    protected $page_num;// 每页多少
+    protected $off_set;
+    protected $is_commit = true; // 事务是否提交
+    protected $ret_msg = ''; // 返回提示信息
+    protected $is_test = false;
+    public function initialize(){
+        $this->page = input('page',1);
+        $this->page_num = input('page_num',20);
+        $this->off_set   =   $this->page * $this->page_num - $this->page_num;
+        $this->is_test = input('test',0);
+    }
+    //校验jwt权限API
+    protected function checkLogin()
+    {
+        $authorization = app()->request->header('Authorization');
+        if(empty($authorization) || $authorization == null){
+           // return true;
+            if($this->is_test == 1) {
+                $this->user_id = 22 ;
+                return true;
+            }
+            $this->error('Token不存在,拒绝访问','',0,-1);
+        }
+        $key = md5(config('app.jwt'));
+        try {
+            $check_authorization = JWT::decode($authorization, $key, array('HS256'));
+            if($check_authorization['code'] !=200) $this->exception($check_authorization['msg']);
+            $authInfo = json_decode(json_encode($check_authorization['data']), true);
+            if (!empty($authInfo['uid'])) {
+                $member = Db::name('store_member')->field('status,is_deleted')->where('id',$authInfo['uid'])->find();
+                if($member['is_deleted'])  $this->error('会员不存在','',0);
+                if($member['status']){
+                    $this->user_id = $authInfo['uid'];
+                    return $this->user_id;
+                }else{
+                    $this->error('该会员已被禁用','',0,-1);
+                }
+            } else {
+                $this->error('Token验证不通过,用户不存在','',0,-1);
+            }
+        } catch (\Exception $e) {
+            $this->error($e->getMessage(),'',0,-1);
+        }
+    }
+
+
+    protected function setUid(){
+        $authorization = app()->request->header('Authorization');
+        $key = md5(config('app.jwt'));
+        if(empty($authorization) || $authorization == null){
+            return false;
+        }
+
+        $check_authorization = JWT::decode($authorization, $key, array('HS256'));
+        if($check_authorization['code'] !=200) return false;
+        $authInfo = json_decode(json_encode($check_authorization['data']), true);
+        if (!empty($authInfo['uid'])) {
+            $member = Db::name('store_member')->field('status')->where('id',$authInfo['uid'])->find();
+            if($member['status']){
+                $this->user_id = $authInfo['uid'];
+                return $this->user_id;
+            }
+        }
+    }
+
+    // 获取用户信息
+    function userInfo($field =''){
+        if(!$this->user_id)  return [];
+        return $field ?  Db::name('store_member')->field($field)->find($this->user_id) : Db::name('store_member')->find($this->user_id);
+    }
+
+    // 验证短信验证码
+    protected function checkPhoneCode($phone,$code){
+        //return true;
+        $sel_time =date('Y-m-d H:i:s',time()-600);
+        $store_member_sms = Db::name('store_member_sms')
+            ->field('id,code')->where('phone',$phone)
+            ->where('create_at','> time',$sel_time)
+            ->where('used',0)->order('id desc')->find();
+        return !empty($store_member_sms) && $store_member_sms['code'] == $code ? $store_member_sms['id'] :0;
+    }
+
+    // 更新验证码状态
+    protected function updatePhoneCode($code_id){
+        Db::name('store_member_sms')->where('id',$code_id)->update(['used'=>1]);
+    }
+    /**
+     * 操作成功返回的数据
+     * @param string $msg   提示信息
+     * @param mixed $data   要返回的数据
+     * @param int   $code   错误码,默认为1
+     * @param string $type  输出类型
+     * @param array $header 发送的 Header 信息
+     */
+    protected function success($msg = '', $data = null , $is_login = 1, $code = 1, $type = null, array $header = [])
+    {
+        $this->results($msg, $data, $is_login, $code, $type, $header);
+    }
+
+    /**
+     * 操作失败返回的数据
+     * @param string $msg   提示信息
+     * @param mixed $data   要返回的数据
+     * @param int   $code   错误码,默认为0
+     * @param string $type  输出类型
+     * @param array $header 发送的 Header 信息
+     */
+    protected function error($msg = '', $data = null, $is_login = 1, $code = 0, $type = null, array $header = [])
+    {
+        if(empty($this->user_id)){
+            $is_login = 0;
+        }
+        $this->results($msg, $data, $is_login, $code, $type, $header);
+    }
+    /**
+     * 返回封装后的 API 数据到客户端
+     * @access protected
+     * @param mixed  $msg    提示信息
+     * @param mixed  $data   要返回的数据
+     * @param int    $code   错误码,默认为0
+     * @param string $type   输出类型,支持json/xml/jsonp
+     * @param array  $header 发送的 Header 信息
+     * @return void
+     * @throws HttpResponseException
+     */
+    protected function results($msg, $data = null, $is_login, $code = 0, $type = null, array $header = [])
+    {
+        $result = [
+            'code' => $code,
+            'is_login' => $is_login,
+            'msg'  => $msg,
+            'time' => \think\facade\Request::instance()->server('REQUEST_TIME'),
+            'data' => $data,
+        ];
+        // 如果未设置类型则自动判断
+        $type = $type ? $type : 'json';
+
+        if (isset($header['statuscode']))
+        {
+            $code = $header['statuscode'];
+            unset($header['statuscode']);
+        }
+        else
+        {
+            //未设置状态码,根据code值判断
+            $code = $code >= 1000 || $code < 200 ? 200 : $code;
+        }
+        $response = Response::create($result, $type, $code)->header($header);
+        throw new HttpResponseException($response);
+    }
+
+
+    //token加密
+    public function createJwt($uid)
+    {
+        $key = md5(config('app.jwt')); //jwt的签发密钥,验证token的时候需要用到
+        $time = time(); //签发时间
+        $expire = $time + config('app.jwt_time'); //过期时间
+        $token = array(
+            "uid" => $uid,
+            "iss" => "https://zain.com",//签发组织
+            "aud" => "https://zain.com", //签发作者
+            "iat" => $time,
+            "nbf" => $time,
+            "exp" => $expire
+        );
+        $jwt = JWT::encode($token, $key);
+        return $jwt;
+    }
+
+    protected function exception($msg){
+        throw new Exception($msg);
+    }
+
+    // 事务返回
+    protected function transReturn($data = []){
+        $this->is_commit ? $this->success($this->ret_msg,$data):$this->error($this->ret_msg);
+    }
+
+
+}

+ 536 - 0
application/api/controller/ChinaSpell.php

@@ -0,0 +1,536 @@
+<?php
+namespace app\api\controller;
+use app\common\model\ChinaArea;
+use think\Db;
+/**
+ * @title 汉字拼音
+ * @controller Area
+ * @group common
+ */
+class ChinaSpell extends Base
+{
+    /**
+     * @var array $chineseSpellList 拼音编码对应表
+     * @access private
+     */
+    private $chineseSpellList = array(
+        'a'=>-20319,
+        'ai'=>-20317,
+        'an'=>-20304,
+        'ang'=>-20295,
+        'ao'=>-20292,
+        'ba'=>-20283,
+        'bai'=>-20265,
+        'ban'=>-20257,
+        'bang'=>-20242,
+        'bao'=>-20230,
+        'bei'=>-20051,
+        'ben'=>-20036,
+        'beng'=>-20032,
+        'bi'=>-20026,
+        'bian'=>-20002,
+        'biao'=>-19990,
+        'bie'=>-19986,
+        'bin'=>-19982,
+        'bing'=>-19976,
+        'bo'=>-19805,
+        'bu'=>-19784,
+        'ca'=>-19775,
+        'cai'=>-19774,
+        'can'=>-19763,
+        'cang'=>-19756,
+        'cao'=>-19751,
+        'ce'=>-19746,
+        'ceng'=>-19741,
+        'cha'=>-19739,
+        'chai'=>-19728,
+        'chan'=>-19725,
+        'chang'=>-19715,
+        'chao'=>-19540,
+        'che'=>-19531,
+        'chen'=>-19525,
+        'cheng'=>-19515,
+        'chi'=>-19500,
+        'chong'=>-19484,
+        'chou'=>-19479,
+        'chu'=>-19467,
+        'chuai'=>-19289,
+        'chuan'=>-19288,
+        'chuang'=>-19281,
+        'chui'=>-19275,
+        'chun'=>-19270,
+        'chuo'=>-19263,
+        'ci'=>-19261,
+        'cong'=>-19249,
+        'cou'=>-19243,
+        'cu'=>-19242,
+        'cuan'=>-19238,
+        'cui'=>-19235,
+        'cun'=>-19227,
+        'cuo'=>-19224,
+        'da'=>-19218,
+        'dai'=>-19212,
+        'dan'=>-19038,
+        'dang'=>-19023,
+        'dao'=>-19018,
+        'de'=>-19006,
+        'deng'=>-19003,
+        'di'=>-18996,
+        'dian'=>-18977,
+        'diao'=>-18961,
+        'die'=>-18952,
+        'ding'=>-18783,
+        'diu'=>-18774,
+        'dong'=>-18773,
+        'dou'=>-18763,
+        'du'=>-18756,
+        'duan'=>-18741,
+        'dui'=>-18735,
+        'dun'=>-18731,
+        'duo'=>-18722,
+        'e'=>-18710,
+        'en'=>-18697,
+        'er'=>-18696,
+        'fa'=>-18526,
+        'fan'=>-18518,
+        'fang'=>-18501,
+        'fei'=>-18490,
+        'fen'=>-18478,
+        'feng'=>-18463,
+        'fo'=>-18448,
+        'fou'=>-18447,
+        'fu'=>-18446,
+        'ga'=>-18239,
+        'gai'=>-18237,
+        'gan'=>-18231,
+        'gang'=>-18220,
+        'gao'=>-18211,
+        'ge'=>-18201,
+        'gei'=>-18184,
+        'gen'=>-18183,
+        'geng'=>-18181,
+        'gong'=>-18012,
+        'gou'=>-17997,
+        'gu'=>-17988,
+        'gua'=>-17970,
+        'guai'=>-17964,
+        'guan'=>-17961,
+        'guang'=>-17950,
+        'gui'=>-17947,
+        'gun'=>-17931,
+        'guo'=>-17928,
+        'ha'=>-17922,
+        'hai'=>-17759,
+        'han'=>-17752,
+        'hang'=>-17733,
+        'hao'=>-17730,
+        'he'=>-17721,
+        'hei'=>-17703,
+        'hen'=>-17701,
+        'heng'=>-17697,
+        'hong'=>-17692,
+        'hou'=>-17683,
+        'hu'=>-17676,
+        'hua'=>-17496,
+        'huai'=>-17487,
+        'huan'=>-17482,
+        'huang'=>-17468,
+        'hui'=>-17454,
+        'hun'=>-17433,
+        'huo'=>-17427,
+        'ji'=>-17417,
+        'jia'=>-17202,
+        'jian'=>-17185,
+        'jiang'=>-16983,
+        'jiao'=>-16970,
+        'jie'=>-16942,
+        'jin'=>-16915,
+        'jing'=>-16733,
+        'jiong'=>-16708,
+        'jiu'=>-16706,
+        'ju'=>-16689,
+        'juan'=>-16664,
+        'jue'=>-16657,
+        'jun'=>-16647,
+        'ka'=>-16474,
+        'kai'=>-16470,
+        'kan'=>-16465,
+        'kang'=>-16459,
+        'kao'=>-16452,
+        'ke'=>-16448,
+        'ken'=>-16433,
+        'keng'=>-16429,
+        'kong'=>-16427,
+        'kou'=>-16423,
+        'ku'=>-16419,
+        'kua'=>-16412,
+        'kuai'=>-16407,
+        'kuan'=>-16403,
+        'kuang'=>-16401,
+        'kui'=>-16393,
+        'kun'=>-16220,
+        'kuo'=>-16216,
+        'la'=>-16212,
+        'lai'=>-16205,
+        'lan'=>-16202,
+        'lang'=>-16187,
+        'lao'=>-16180,
+        'le'=>-16171,
+        'lei'=>-16169,
+        'leng'=>-16158,
+        'li'=>-16155,
+        'lia'=>-15959,
+        'lian'=>-15958,
+        'liang'=>-15944,
+        'liao'=>-15933,
+        'lie'=>-15920,
+        'lin'=>-15915,
+        'ling'=>-15903,
+        'liu'=>-15889,
+        'long'=>-15878,
+        'lou'=>-15707,
+        'lu'=>-15701,
+        'lv'=>-15681,
+        'luan'=>-15667,
+        'lue'=>-15661,
+        'lun'=>-15659,
+        'luo'=>-15652,
+        'ma'=>-15640,
+        'mai'=>-15631,
+        'man'=>-15625,
+        'mang'=>-15454,
+        'mao'=>-15448,
+        'me'=>-15436,
+        'mei'=>-15435,
+        'men'=>-15419,
+        'meng'=>-15416,
+        'mi'=>-15408,
+        'mian'=>-15394,
+        'miao'=>-15385,
+        'mie'=>-15377,
+        'min'=>-15375,
+        'ming'=>-15369,
+        'miu'=>-15363,
+        'mo'=>-15362,
+        'mou'=>-15183,
+        'mu'=>-15180,
+        'na'=>-15165,
+        'nai'=>-15158,
+        'nan'=>-15153,
+        'nang'=>-15150,
+        'nao'=>-15149,
+        'ne'=>-15144,
+        'nei'=>-15143,
+        'nen'=>-15141,
+        'neng'=>-15140,
+        'ni'=>-15139,
+        'nian'=>-15128,
+        'niang'=>-15121,
+        'niao'=>-15119,
+        'nie'=>-15117,
+        'nin'=>-15110,
+        'ning'=>-15109,
+        'niu'=>-14941,
+        'nong'=>-14937,
+        'nu'=>-14933,
+        'nv'=>-14930,
+        'nuan'=>-14929,
+        'nue'=>-14928,
+        'nuo'=>-14926,
+        'o'=>-14922,
+        'ou'=>-14921,
+        'pa'=>-14914,
+        'pai'=>-14908,
+        'pan'=>-14902,
+        'pang'=>-14894,
+        'pao'=>-14889,
+        'pei'=>-14882,
+        'pen'=>-14873,
+        'peng'=>-14871,
+        'pi'=>-14857,
+        'pian'=>-14678,
+        'piao'=>-14674,
+        'pie'=>-14670,
+        'pin'=>-14668,
+        'ping'=>-14663,
+        'po'=>-14654,
+        'pu'=>-14645,
+        'qi'=>-14630,
+        'qia'=>-14594,
+        'qian'=>-14429,
+        'qiang'=>-14407,
+        'qiao'=>-14399,
+        'qie'=>-14384,
+        'qin'=>-14379,
+        'qing'=>-14368,
+        'qiong'=>-14355,
+        'qiu'=>-14353,
+        'qu'=>-14345,
+        'quan'=>-14170,
+        'que'=>-14159,
+        'qun'=>-14151,
+        'ran'=>-14149,
+        'rang'=>-14145,
+        'rao'=>-14140,
+        're'=>-14137,
+        'ren'=>-14135,
+        'reng'=>-14125,
+        'ri'=>-14123,
+        'rong'=>-14122,
+        'rou'=>-14112,
+        'ru'=>-14109,
+        'ruan'=>-14099,
+        'rui'=>-14097,
+        'run'=>-14094,
+        'ruo'=>-14092,
+        'sa'=>-14090,
+        'sai'=>-14087,
+        'san'=>-14083,
+        'sang'=>-13917,
+        'sao'=>-13914,
+        'se'=>-13910,
+        'sen'=>-13907,
+        'seng'=>-13906,
+        'sha'=>-13905,
+        'shai'=>-13896,
+        'shan'=>-13894,
+        'shang'=>-13878,
+        'shao'=>-13870,
+        'she'=>-13859,
+        'shen'=>-13847,
+        'sheng'=>-13831,
+        'shi'=>-13658,
+        'shou'=>-13611,
+        'shu'=>-13601,
+        'shua'=>-13406,
+        'shuai'=>-13404,
+        'shuan'=>-13400,
+        'shuang'=>-13398,
+        'shui'=>-13395,
+        'shun'=>-13391,
+        'shuo'=>-13387,
+        'si'=>-13383,
+        'song'=>-13367,
+        'sou'=>-13359,
+        'su'=>-13356,
+        'suan'=>-13343,
+        'sui'=>-13340,
+        'sun'=>-13329,
+        'suo'=>-13326,
+        'ta'=>-13318,
+        'tai'=>-13147,
+        'tan'=>-13138,
+        'tang'=>-13120,
+        'tao'=>-13107,
+        'te'=>-13096,
+        'teng'=>-13095,
+        'ti'=>-13091,
+        'tian'=>-13076,
+        'tiao'=>-13068,
+        'tie'=>-13063,
+        'ting'=>-13060,
+        'tong'=>-12888,
+        'tou'=>-12875,
+        'tu'=>-12871,
+        'tuan'=>-12860,
+        'tui'=>-12858,
+        'tun'=>-12852,
+        'tuo'=>-12849,
+        'wa'=>-12838,
+        'wai'=>-12831,
+        'wan'=>-12829,
+        'wang'=>-12812,
+        'wei'=>-12802,
+        'wen'=>-12607,
+        'weng'=>-12597,
+        'wo'=>-12594,
+        'wu'=>-12585,
+        'xi'=>-12556,
+        'xia'=>-12359,
+        'xian'=>-12346,
+        'xiang'=>-12320,
+        'xiao'=>-12300,
+        'xie'=>-12120,
+        'xin'=>-12099,
+        'xing'=>-12089,
+        'xiong'=>-12074,
+        'xiu'=>-12067,
+        'xu'=>-12058,
+        'xuan'=>-12039,
+        'xue'=>-11867,
+        'xun'=>-11861,
+        'ya'=>-11847,
+        'yan'=>-11831,
+        'yang'=>-11798,
+        'yao'=>-11781,
+        'ye'=>-11604,
+        'yi'=>-11589,
+        'yin'=>-11536,
+        'ying'=>-11358,
+        'yo'=>-11340,
+        'yong'=>-11339,
+        'you'=>-11324,
+        'yu'=>-11303,
+        'yuan'=>-11097,
+        'yue'=>-11077,
+        'yun'=>-11067,
+        'za'=>-11055,
+        'zai'=>-11052,
+        'zan'=>-11045,
+        'zang'=>-11041,
+        'zao'=>-11038,
+        'ze'=>-11024,
+        'zei'=>-11020,
+        'zen'=>-11019,
+        'zeng'=>-11018,
+        'zha'=>-11014,
+        'zhai'=>-10838,
+        'zhan'=>-10832,
+        'zhang'=>-10815,
+        'zhao'=>-10800,
+        'zhe'=>-10790,
+        'zhen'=>-10780,
+        'zheng'=>-10764,
+        'zhi'=>-10587,
+        'zhong'=>-10544,
+        'zhou'=>-10533,
+        'zhu'=>-10519,
+        'zhua'=>-10331,
+        'zhuai'=>-10329,
+        'zhuan'=>-10328,
+        'zhuang'=>-10322,
+        'zhui'=>-10315,
+        'zhun'=>-10309,
+        'zhuo'=>-10307,
+        'zi'=>-10296,
+        'zong'=>-10281,
+        'zou'=>-10274,
+        'zu'=>-10270,
+        'zuan'=>-10262,
+        'zui'=>-10260,
+        'zun'=>-10256,
+        'zuo'=>-10254
+    );
+
+    //得到汉字拼音首字母
+    public function getFirstChar($str){
+        $fchar = ord($str{0});
+        if($fchar >= ord("A") and $fchar <= ord("z") )return strtoupper($str{0});
+        $s1 = mb_convert_encoding($str,"gb2312");
+        $s2 = mb_convert_encoding($s1, "UTF-8");
+        if($s2 == $str){$s = $s1;}else{$s = $str;}
+        $asc = ord($s{0}) * 256 + ord($s{1}) - 65536;
+        if($asc >= -20319 and $asc <= -20284) return "A";
+        if($asc >= -20283 and $asc <= -19776) return "B";
+        if($asc >= -19775 and $asc <= -19219) return "C";
+        if($asc >= -19218 and $asc <= -18711) return "D";
+        if($asc >= -18710 and $asc <= -18527) return "E";
+        if($asc >= -18526 and $asc <= -18240) return "F";
+        if($asc >= -18239 and $asc <= -17923) return "G";
+        if($asc >= -17922 and $asc <= -17418) return "H";
+        if($asc >= -17922 and $asc <= -17418) return "I";
+        if($asc >= -17417 and $asc <= -16475) return "J";
+        if($asc >= -16474 and $asc <= -16213) return "K";
+        if($asc >= -16212 and $asc <= -15641) return "L";
+        if($asc >= -15640 and $asc <= -15166) return "M";
+        if($asc >= -15165 and $asc <= -14923) return "N";
+        if($asc >= -14922 and $asc <= -14915) return "O";
+        if($asc >= -14914 and $asc <= -14631) return "P";
+        if($asc >= -14630 and $asc <= -14150) return "Q";
+        if($asc >= -14149 and $asc <= -14091) return "R";
+        if($asc >= -14090 and $asc <= -13319) return "S";
+        if($asc >= -13318 and $asc <= -12839) return "T";
+        if($asc >= -12838 and $asc <= -12557) return "W";
+        if($asc >= -12556 and $asc <= -11848) return "X";
+        if($asc >= -11847 and $asc <= -11056) return "Y";
+        if($asc >= -11055 and $asc <= -10247) return "Z";
+        return NULL;
+    }
+
+
+    public function pinYinLong($zh)
+    {  //获取整条字符串汉字拼音首字母
+        $ret = "";
+        $s1 = iconv("UTF-8", "gb2312", $zh);
+        $s2 = iconv("gb2312", "UTF-8", $s1);
+        if ($s2 == $zh) {
+            $zh = $s1;
+        }
+        for ($i = 0; $i < strlen($zh); $i++) {
+            $s1 = substr($zh, $i, 1);
+            $p = ord($s1);
+            if ($p > 160) {
+                $s2 = substr($zh, $i++, 2);
+                $ret .= $this->getFirstChar($s2);
+            } else {
+                $ret .= $s1;
+            }
+        }
+        return $ret;
+
+    }
+
+
+    /**
+     * 取汉字所有拼音
+     * @param string $chinese 要转换的汉字
+     * @param string $delimiter 分隔符
+     * @param int $length 返回的长度
+     * @return string
+     */
+    public function getFullSpell($chinese, $delimiter = '', $length = 0){
+        $spell = $this->getChineseSpells($chinese, $delimiter);
+        if($length){
+            $spell = substr($spell, 0, $length);
+        }
+        return $spell;
+    }
+
+    /**
+     * 取一个汉字码对应的拼音
+     * @param int $num 汉字码
+     * @param string $blank 空白字符
+     * @return string
+     */
+    public function getChineseSpell ($num, $blank = ''){
+        if($num>0 && $num<160){
+            return chr($num);
+        }
+        elseif($num<-20319||$num>-10247){
+            return $blank;
+        }
+        else{
+            foreach ($this->chineseSpellList as $spell => $code){
+                if ($code > $num) break;
+                $result = $spell;
+            }
+            return $result;
+        }
+    }
+
+    /**
+     * 取汉字拼音
+     * @param string $chinese 要转换的汉字
+     * @param string $delimiter 分隔符
+     * @param int $first 是否只返回第一个
+     * @return string
+     */
+    public function getChineseSpells($chinese, $delimiter = '', $first=0){
+        $chinese = mb_convert_encoding($chinese, "GBK");
+        $result = array();
+        for($i=0; $i<strlen($chinese); $i++){
+            $p = ord(substr($chinese,$i,1));
+            if($p>160){
+                $q = ord(substr($chinese,++$i,1));
+                $p = $p*256 + $q - 65536;
+            }
+            $result[] = $this->getChineseSpell($p);
+            if($first){
+                return $result[0];
+            }
+        }
+        return implode($delimiter, $result);
+    }
+
+
+}

+ 284 - 0
application/api/controller/Collect.php

@@ -0,0 +1,284 @@
+<?php
+namespace app\api\controller;
+use app\common\model\NewsCate;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\UserCollect;
+use app\common\model\InformationArticle;
+use app\common\model\VideoCate;
+use app\common\model\VideoIntro;
+use app\common\model\GoodsCate;
+use think\Db;
+use library\tools\Data;
+/**
+ * @title 收藏
+ * @controller Collect
+ * @group base
+ */
+class Collect extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 获取收藏标题设置
+     * @desc 获取收藏标题设置
+     * @author qc
+     * @method GET
+     * @url /api/Collect/getCollectSet
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:string default:-- desc:标题
+     * @return name:num type:string default:-- desc:收藏数量
+     * @return name:type type:string default:-- desc:类型
+     * @return name:time_arr type:array default:-- desc:时间搜索数组
+     * @return name:cate_arr type:array default:-- desc:收藏分类
+     * @return name:cate_arr.time_key type:int default:-- desc:时间筛选查询使用
+     * @return name:cate_arr.id type:int default:-- desc:收藏分类id
+     * @return name:cate_arr.title type:array default:-- desc:分类名
+     * @return name:cate_arr.logo type:string default:-- desc:分类logo
+     * @return name:all_num type:int default:-- desc:收藏总量
+     */
+    public function getCollectSet()
+    {
+        $time_arr = [
+            ['name'=>'7天内'  ,   'time_key'=>1],
+            ['name'=>'30天内' ,   'time_key'=>2],
+            ['name'=>'90天内',    'time_key'=>3],
+            ['name'=>'半年前',    'time_key'=>4],
+            ['name'=>'一年前',    'time_key'=>5]];
+        $collect_all = [
+            ['title'=>'宝贝','type'=>1,'time_arr'=>$time_arr,'cate_arr'=>[]],
+            ['title'=>'资讯','type'=>2,'time_arr'=>$time_arr,'cate_arr'=>[]],
+           // ['title'=>'视频','type'=>3,'time_arr'=>$time_arr,'cate_arr'=>[]],
+        ];
+        $all_num =  UserCollect::where(['user_id'=>$this->user_id])->count();
+        foreach ($collect_all as &$value)
+        {
+            $coll_list =   UserCollect::field('cate_id')->where(['user_id'=>$this->user_id,'coll_type'=>$value['type']])->group('cate_id')->select();
+            if(!$coll_list) continue;
+            $coll_list = $coll_list->toArray();
+            switch ($value['type']){
+                case 1:
+                    $value['cate_arr'] = GoodsCate::field('id,title,logo')->where('id','in',array_column($coll_list,'cate_id'))->select();
+                    break;
+                case 2:
+                    $value['cate_arr'] = NewsCate::field('id,title,logo')->where('id','in',array_column($coll_list,'cate_id'))->select();
+                    break;
+                case 3:
+                    $value['cate_arr'] = VideoCate::field('id,title,logo')->where('id','in',array_column($coll_list,'cate_id'))->select();
+                    break;
+            }
+        }
+        $this->success('ok',['collect'=>$collect_all,'all_num'=>$all_num]);
+    }
+
+
+    /**
+     * @title 用户收藏(单个收藏)
+     * @desc 用户收藏(单个收藏)
+     * @author qc
+     * @method POST
+     * @url /api/Collect/userCollect
+     * @header name:Authorization require:1 desc:Token
+     * @param name:coll_type type:int require:1 default:-- desc:类型(1商品2资讯3视频)
+     * @param name:coll_id type:int require:1 default:-- desc:收藏id
+     * @param name:cate_id type:int require:1 default:-- desc:收藏分类id(字段:first_classify)
+     * @param name:status type:int default:0 desc:收藏状态(0取消收藏【未收藏】,1收藏)
+     */
+    public function userCollect()
+    {
+        $coll_type  = input('post.coll_type',0);
+        $coll_id    = input('post.coll_id',0);
+        $cate_id    = input('post.cate_id',0);
+        $collect_check = UserCollect::where(['user_id'=>$this->user_id,'coll_type'=>$coll_type,'coll_id'=>$coll_id])->find();
+        if($collect_check) {
+            UserCollect::where(['user_id'=>$this->user_id,'coll_type'=>$coll_type,'coll_id'=>$coll_id])->delete();
+            $this->success('取消收藏成功',['status'=>0]);
+        }else{
+            Data::save('UserCollect', [
+                'user_id'=>$this->user_id,
+                'coll_type'=>$coll_type,
+                'coll_id'=>$coll_id,
+                'cate_id'=>$cate_id,
+                'create_int'=>time()],'user_id',['user_id'=>$this->user_id,'coll_type'=>$coll_type, 'coll_id'=>$coll_id]);
+            $this->success('收藏成功',['status'=>1]);
+        }
+
+    }
+
+    /**
+     * @title 用户收藏(批量收藏)
+     * @desc 用户收藏(批量收藏)
+     * @author qc
+     * @method POST
+     * @url /api/Collect/userBatchCollect
+     * @header name:Authorization require:1 desc:Token
+     * @param name:coll_type type:int require:1 default:-- desc:类型(1商品2资讯3视频)
+     * @param name:ids type:string require:1 default:-- desc:收藏id(多个逗号隔开)
+     */
+    public function userBatchCollect()
+    {
+        $coll_type  = input('post.coll_type',1);
+        $ids        = input('post.ids',0);
+        //$ids=explode(',',$ids);
+        $insert_data = [];
+        switch ($coll_type){
+            case 1:
+                $batch_data = StoreGoods::field('id,first_classify')->where('id','in',$ids)->select();
+                break;
+            case 2:
+                $batch_data = InformationArticle::field('id,first_classify')->where('id','in',$ids)->select();
+                break;
+            case 3:
+                $batch_data = VideoIntro::field('id,first_classify')->where('id','in',$ids)->select();
+                break;
+        }
+        foreach ($batch_data as $vv){
+            $collect_check = UserCollect::where(['user_id'=>$this->user_id,'coll_type'=>$coll_type,'coll_id'=>$vv->id])->find();
+            if($collect_check) continue;
+            $vv->cate_id = $vv->first_classify;
+            $insert_data[] = [
+                'user_id' => $this->user_id,
+                'coll_id' => $vv->id,
+                'coll_type' =>$coll_type,
+                'create_at' =>date('Y-m-d H:i:s'),
+                'create_int' =>time(),
+                'cate_id' =>$vv->cate_id,
+            ];
+        }
+        if(!empty($insert_data)) (new UserCollect())->saveAll($insert_data);
+
+        $this->success('收藏成功');
+    }
+
+
+    /**
+     * @title 获取用户收藏列表
+     * @desc 获取用户收藏列表
+     * @author qc
+     * @method GET
+     * @url /api/Collect/getUserCollectList
+     * @header name:Authorization require:1 desc:Token
+     * @param name:page type:int  default:1 desc:页数
+     * @param name:page_num type:int  : default:20 desc:每页数
+     * @param name:coll_type type:int require:1 default:-- desc:类型(1商品2资讯3视频)
+     * @param name:cate_id type:int require:1 default:0 desc:收藏分类id
+     * @param name:time_key type:int require:1 default:0 desc:时间time_key
+     * @return name:id type:int default:-- desc:记录id
+     * @return name:coll_id type:int default:-- desc:收藏id
+     * @return name:coll_type type:int default:-- desc:收藏类型
+     * @return name:goods_name type:string default:-- desc:商品名称(coll_type=1)
+     * @return name:cover type:string default:-- desc:商品封面(coll_type=1)
+     * @return name:line_money type:string default:-- desc:下划线价格(coll_type=1)
+     * @return name:low_price type:float default:-- desc:最低价(coll_type=1)
+     * @return name:article_title type:string default:-- desc:文章标题(coll_type=2)
+     * @return name:article_cover type:string default:-- desc:文章封面(coll_type=2)
+     * @return name:read_num type:int default:-- desc:阅读热人数(coll_type=2)
+     * @return name:video_title type:string default:-- desc:视频标题(coll_type=3)
+     * @return name:video_url type:string default:-- desc:视频链接(coll_type=3)
+     */
+    public function getUserCollectList()
+    {
+        $coll_type = input('get.coll_type',1);
+        $cate_id = input('get.cate_id',0);
+        $time_key = input('get.time_key',0);
+        $sel_where = [];
+        $sel_where[] = ['c.coll_type','=',$coll_type];
+        $sel_where[] = ['c.user_id','=',$this->user_id];
+        if($cate_id)$sel_where[] = ['c.cate_id','=',$cate_id];
+        // 时间查询
+        switch ($time_key){
+            case 1:
+                $sel_where[] = ['c.create_int','>',time() - 7 * 86400];
+                break;
+            case 2:
+                $sel_where[] = ['c.create_int','>',time() - 30 * 86400];
+                break;
+            case 3:
+                $sel_where[] = ['c.create_int','>',time() - 90 * 86400];
+                break;
+            case 4:
+                $sel_where[] = ['c.create_int','between',[time()- 182 * 86400,time() - 365 * 86400]];
+                break;
+            case 5:
+                $sel_where[] = ['c.create_int','<',time() - 365 * 86400];
+                break;
+        }
+        switch ($coll_type){
+            case 1 :
+                $list = Db::name('user_collect')->alias('c')
+                    ->field('c.id,c.coll_id,c.coll_type,c.cate_id,g.name as goods_name, g.cover , g.low_price')
+                    ->join('store_goods g','c.coll_id = g.id','LEFT')
+                    ->where($sel_where)
+                    ->limit($this->off_set,$this->page_num)
+                    ->order('c.create_int desc')
+                    ->select();
+                foreach ($list as &$v) {
+                    $v['line_money']=StoreGoodsItem::where(['goods_id'=>$v['coll_id']])->max('original_price');
+                }
+                break;
+            case 2 :
+                $list = Db::name('user_collect')->alias('c')
+                    ->field('c.id,c.coll_id,c.coll_type,c.cate_id,g.title as article_title ,g.cover as article_cover, g.read_num')
+                    ->join('information_article g','c.coll_id = g.id','LEFT')
+                    ->where($sel_where)
+                    ->limit($this->off_set,$this->page_num)
+                    ->order('c.create_int desc')
+                    ->select();
+                break;
+            case 3 :
+                $list = Db::name('user_collect')->alias('c')
+                    ->field('c.id,c.coll_id,c.coll_type,c.cate_id,g.title as video_title , g.video_url')
+                    ->join('dd_video_intro g','c.coll_id = g.id','LEFT')
+                    ->where($sel_where)
+                    ->limit($this->off_set,$this->page_num)
+                    ->order('c.create_int desc')
+                    ->select();
+                break;
+        }
+        $this->success('ok',['list'=>$list]);
+
+    }
+
+    /**
+     * @title 取消收藏
+     * @desc 取消收藏
+     * @author qc
+     * @method POST
+     * @url /api/Collect/cancelCollect
+     * @header name:Authorization require:1 desc:Token
+     * @param name:ids type:string  : default:'' desc:需要删除的id记录(用逗号隔开)
+     */
+    public function cancelCollect()
+    {
+        $ids = input('post.ids','');
+        if(!$ids) $this->error('请选择要取消收藏的记录');
+        UserCollect::where('id','in',$ids)->where('user_id','=',$this->user_id)->delete();
+        $this->success('取消成功');
+    }
+
+    /**
+     * @title 取消收藏
+     * @desc 根据类型和(商品id||资讯id||视频id)取消
+     * @author qc
+     * @method POST
+     * @url /api/Collect/cancelCollectByType
+     * @header name:Authorization require:1 desc:Token
+     * @param name:coll_type type:int require:1 default:1s desc:类型(1商品2资讯3视频)
+     * @param name:coll_id type:int default:1 desc:取消收藏的id(商品||资讯||视频)
+     */
+    public function cancelCollectByType()
+    {
+        $coll_type = input('post.coll_type',1);
+        $coll_id = input('get.coll_id',0);
+        UserCollect::where(['user_id'=>$this->user_id,'coll_type'=>$coll_type,'coll_id'=>$coll_id])->delete();
+        $this->success('取消成功');
+    }
+
+
+
+
+}

+ 388 - 0
application/api/controller/CustomOrder.php

@@ -0,0 +1,388 @@
+<?php
+namespace app\api\controller;
+use app\common\model\DeliveryAddress;
+use app\common\model\GiftGoods;
+use app\common\model\GiftOrder;
+use app\common\model\GoodsOrderItem;
+use app\common\model\OrderUrge;
+use app\common\model\StoreGoodsItem;
+use app\common\model\User;
+use app\common\model\UserWallet;
+use app\common\service\OrderCallback;
+use EasyWeChat\Factory;
+use think\Db;
+
+/**
+ * @title 定制订单
+ * @controller CustomOrder
+ * @group base
+ */
+class CustomOrder extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 生成订单(立即购买)
+     * @desc  立即购买场景
+     * @author  qc
+     * @url /api/Custom_order/creatOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:goods_id type:int require:1  default:0 desc:商品id
+     * @param name:spec_id type:int require:1  default:0 desc:规格id(item_list下面id)
+     * @param name:gift_cate type:int require:1  default:0 desc:定制分类
+     * @param name:num type:int default:1 desc:数量
+     * @param name:title type:string default:1 desc:包装名称
+     * @param name:logo type:string default:1 desc:logo
+     * @param name:custom_cover type:string default:1 desc:风格(图片路径)
+     * @param name:custom_color type:string default:1 desc:颜色(图片路径)
+     * @param name:self_cover type:string default:0 desc:自定义图片(多张逗号分开,最多三张)
+     * @param name:remark type:string default:1 desc:订单备注
+     * @param name:add_id type:int default:1 desc:收货地址id
+     * @return name:order_id type:int default:1 desc:订单id
+     */
+    public function creatOrder()
+    {
+        $goods_id = input('post.goods_id',0);
+        $spec_id = input('post.spec_id',0);
+        $num = input('post.num',0);
+        $gift_cate = input('post.gift_cate',0);
+        $title = input('post.title');
+        $logo = input('post.logo');
+        $custom_cover = input('post.custom_cover');
+        $custom_color = input('post.custom_color');
+        $self_cover = input('post.self_cover');
+        $remark = input('post.remark');
+        $add_id =  input('post.add_id');
+        if(!$add_id) $this->error('请选择收货地址');
+        $add_info = DeliveryAddress::where('id',$add_id)->find();
+        $add_info = $add_info ?  $add_info->toArray(): ['pro_name'=>'','city_name'=>'','county_name'=>'','street_name'=>'','name'=>'','detail'=>'','phone'=>''];
+        $goods_info = GiftGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->alias('s')
+            ->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.status'=>1,'s.is_custom'=>1,'s.is_deleted'=>0,'g.is_deleted'=>0,'g.status'=>1,'s.goods_id'=>$goods_id,'s.cate_id'=>$gift_cate])
+            ->find();
+        if(!$goods_info) $this->error('商品已下架');
+        // 规格详情
+        $item_info = StoreGoodsItem::where('id',$spec_id)->find()->toArray();
+        if($item_info['stock'] < $num ) $this->error('商品库存不足');
+        if($item_info['status'] == 0) $this->error('改规格已下架');
+        if($item_info['status'] == 0 || $item_info['is_deleted'] == 1) $this->error('改规格已下架');
+        $order_insert = [
+            'user_id' => $this->user_id,
+            'order_no' => get_order_sn(),
+            'goods_id' => $goods_id,
+            'spec_id' => $spec_id,
+            'goods_num' => $num,
+            'price_total' => bcmul($num,$item_info['sell_price']),
+            'price_goods' => bcmul($num,$item_info['sell_price']),
+            'pro_name' => $add_info['pro_name'],
+            'city_name' => $add_info['city_name'],
+            'county_name' => $add_info['county_name'],
+            'street_name' => $add_info['street_name'],
+            'user_name' => $add_info['name'],
+            'add_detail' => $add_info['detail'],
+            'phone' => $add_info['phone'],
+            'custom_cover' => $custom_cover,
+            'logo' => $logo,
+            'remark' => $remark,
+            'custom_color' => $custom_color,
+            'self_cover' => $self_cover,
+            'title' => $title,
+            'gift_cate' => $gift_cate,
+        ];
+        $res  = GiftOrder::create($order_insert);
+        StoreGoodsItem::where('id',$spec_id)->setDec('stock',$num);
+        $this->success('定制订单已提交',['order_id'=>$res->id]);
+    }
+
+    /**
+     * @title 获取订单列表
+     * @desc 待审核:sh_status=0;待付款:sh_status=1&&status=0;待发货:status=1;待收货:status=3;
+     * @author qc
+     * @method GET
+     * @url /api/Custom_order/getCustomOrderList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数
+     * @param  name:status type:int default:-1  desc:状态(0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,8已退款,9取消)
+     * @param  name:sh_status type:int default:-1  desc:审核状态(0待审核1审核通过2审核拒绝)
+     * @return name:id type:int default:--  desc:订单id
+     * @return name:order_no type:string default:--  desc:订单号
+     * @return name:price_total type:float default:--  desc:待支付金额(商品价格+运费+包装费)
+     * @return name:price_goods type:float default:--  desc:商品金额
+     * @return name:price_express type:float default:--  desc:运费金额
+     * @return name:price_pack type:float default:--  desc:包装费
+     * @return name:pay_state type:int default:--  desc:支付状态(0未支付1已支付)
+     * @return name:pay_type type:int default:--  desc:支付方式(1微信2余额3支付宝)
+     * @return name:pay_no type:string default:--  desc:支付号
+     * @return name:pay_at type:string default:--  desc:支付时间
+     * @return name:cancel_state type:int default:--  desc:取消状态(0未取消1已取消)
+     * @return name:cancel_at type:string default:--  desc:取消时间
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:express_state type:int default:--  desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_title type:string default:--  desc:发货快递公司名称
+     * @return name:express_send_no type:string default:--  desc:物流单号
+     * @return name:express_send_at type:string default:--  desc:发货时间
+     * @return name:status type:int default:--  desc:订单状态(0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,8已退款,9取消)
+     * @return name:create_at type:string default:--  desc:下单时间
+     * @return name:remark type:string default:--  desc:订单备注
+     * @return name:goods_id type:int default:--  desc:订单商品id
+     * @return name:goods_num type:int default:--  desc:订单商品总数量
+     * @return name:pro_name type:string default:--  desc:省名称(收货地址)
+     * @return name:city_name type:string default:--  desc:市名称(收货地址)
+     * @return name:county_name type:string default:--  desc:县区名称(收货地址)
+     * @return name:street_name type:string default:--  desc:街道名称(收货地址)
+     * @return name:add_detail type:string default:--  desc:详细地址(收货地址)
+     * @return name:user_name type:string default:--  desc:收货人
+     * @return name:phone type:string default:--  desc:收货人联系电话
+     * @return name:goods_spec type:string default:--  desc:商品规格
+     * @return name:sell_price type:string default:--  desc:售价(单价【不含包装】)
+     * @return name:spec_title type:string default:--  desc:规格标题
+     * @return name:goods type:array default:--  desc:订单商品
+     * @return name:goods.name type:string default:--  desc:商品名
+     * @return name:goods.cover type:string default:--  desc:商品封面
+     */
+    public function getCustomOrderList()
+    {
+        $status = input('get.status',-1);
+        $sh_status = input('get.sh_status',-1);
+        $where = [];
+        $where[] = ['o.user_id','=',$this->user_id];
+        if($status > -1) $where[] = ['o.status','=',$status];
+        if($sh_status > -1) $where[] = ['o.sh_status','=',$sh_status];
+        $list = GiftOrder::with('goods')
+            ->field('o.*,i.goods_spec,i.sell_price,i.spec_title')
+            ->leftJoin('StoreGoodsItem i','i.id = o.spec_id')
+            ->alias('o')
+            ->where($where)->order('id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        $this->success('',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取订单详情
+     * @desc 获取订单详情
+     * @author qc
+     * @method GET
+     * @url /api/Custom_order/getCustomOrderDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int  default:1 desc:订单id
+     * @return name:id type:int default:--  desc:订单id
+     * @return name:order_no type:string default:--  desc:订单号
+     * @return name:price_total type:float default:--  desc:待支付金额(商品价格+运费+包装费)
+     * @return name:price_goods type:float default:--  desc:商品金额
+     * @return name:price_express type:float default:--  desc:运费金额
+     * @return name:price_pack type:float default:--  desc:包装费
+     * @return name:pay_state type:int default:--  desc:支付状态(0未支付1已支付)
+     * @return name:pay_type type:int default:--  desc:支付方式(1微信2余额3支付宝)
+     * @return name:pay_no type:string default:--  desc:支付号
+     * @return name:pay_at type:string default:--  desc:支付时间
+     * @return name:cancel_state type:int default:--  desc:取消状态(0未取消1已取消)
+     * @return name:cancel_at type:string default:--  desc:取消时间
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:express_state type:int default:--  desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_title type:string default:--  desc:发货快递公司名称
+     * @return name:express_send_no type:string default:--  desc:物流单号
+     * @return name:express_send_at type:string default:--  desc:发货时间
+     * @return name:status type:int default:--  desc:订单状态(0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,8已退款,9取消)
+     * @return name:create_at type:string default:--  desc:下单时间
+     * @return name:remark type:string default:--  desc:订单备注
+     * @return name:goods_id type:int default:--  desc:订单商品id
+     * @return name:goods_num type:int default:--  desc:订单商品总数量
+     * @return name:pro_name type:string default:--  desc:省名称(收货地址)
+     * @return name:city_name type:string default:--  desc:市名称(收货地址)
+     * @return name:county_name type:string default:--  desc:县区名称(收货地址)
+     * @return name:street_name type:string default:--  desc:街道名称(收货地址)
+     * @return name:add_detail type:string default:--  desc:详细地址(收货地址)
+     * @return name:user_name type:string default:--  desc:收货人
+     * @return name:phone type:string default:--  desc:收货人联系电话
+     * @return name:goods type:array default:--  desc:订单商品
+     * @return name:goods.name type:string default:--  desc:商品名
+     * @return name:goods.cover type:string default:--  desc:商品封面
+     * @return name:goods_spec type:string default:--  desc:商品规格
+     * @return name:sell_price type:string default:--  desc:售价(单价【不含包装】)
+     * @return name:spec_title type:string default:--  desc:规格标题
+     */
+    public function getCustomOrderDetail()
+    {
+        $order_id =input('get.order_id');
+        $detail = GiftOrder::with(['goods'])->where('id',$order_id)->find()->toArray();
+        $item = StoreGoodsItem::field('goods_spec,sell_price,spec_title')->where('id',$detail['spec_id'])->find()->toArray();
+        $detail['goods_spec'] = $item['goods_spec'];
+        $detail['sell_price'] = $item['sell_price'];
+        $detail['spec_title'] = $item['spec_title'];
+        $this->success('',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 取消订单
+     * @desc  取消订单
+     * @author  qc
+     * @url /api/Custom_order/cancelOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:cancel_desc type:string require:0  default:0 desc:取消描述
+     */
+    public function cancelOrder()
+    {
+        $order_id = input('post.order_id');
+        $cancel_desc = input('post.cancel_desc');
+        $order_info = GiftOrder::where('id',$order_id)->find();
+        if($order_info['status'] != 0) $this->error('订单已支付');
+        if($order_info['is_deleted'] != 0) $this->error('订单不存在');
+        if($order_info['cancel_state'] != 0) $this->error('订单已取消');
+        $order_info->cancel_state = 1;
+        $order_info->status = 9;
+        $order_info->cancel_at = date('Y-m-d H:i:s');
+        $order_info->cancel_desc = $cancel_desc;
+        $order_info->save();
+        $this->success('订单已取消');
+    }
+
+    /**
+     * @title 删除订单
+     * @desc  删除订单
+     * @author  qc
+     * @url /api/Custom_order/deleteOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function deleteOrder()
+    {
+        $order_id = input('post.order_id');
+        $detail = GiftOrder::where('id',$order_id)->find()->toArray();
+        if(!in_array($detail['status'],[0,9])) $this->error('订单已支付');
+        GiftOrder::update(['is_deleted'=>1],['id'=>$order_id]);
+        $this->success('删除成功');
+    }
+
+
+    /**
+     * @title 订单支付
+     * @desc  订单支付
+     * @author  qc
+     * @url /api/Custom_order/payOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:pay_type type:int require:1  default:0 desc:支付方式
+     */
+    public function payOrder()
+    {
+        $order_id  = input('post.order_id');
+        $pay_type  = input('post.pay_type');
+        $ret_data = ['pay_status'=>0,'config'=>[],'code_url'=>''];
+        Db::startTrans();
+        try {
+            $order_info = GiftOrder::where('id',$order_id)->find()->toArray();
+            if($order_info['status'] != 0) $this->exception('订单状态错误');
+            if($order_info['sh_status'] == 0) $this->exception('订单未审核');
+            if($order_info['sh_status'] == 2) $this->exception('审核未通过');
+            $pay_no  = $order_info['pay_no'] ? $order_info['pay_no']:get_order_sn();// 支付单号
+            if(!$order_info['pay_no']) GiftOrder::where('id',$order_id)->update(['pay_no'=>$pay_no]);
+            $user_info = User::with('wallet')->where('id',$this->user_id)->find()->toArray();
+            switch ($pay_type){
+                case 1://微信小程序
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/customOrderNotify';
+                    $pay_config = WeChatPay::wxPay('订单支付',$pay_no,$order_info['price_total'],$notify_url,'JSAPI',$user_info['openid']);
+                    if($pay_config['code'] != 200) $this->exception($pay_config['msg']);
+                    $ret_data['config'] = $pay_config['config'];
+                    break;
+                case 2://佣金余额
+                    if($user_info['wallet']['money'] < $order_info['price_total'])$this->exception('余额不足');
+                    // 扣除余额
+                    UserWallet::userMoneyChange($this->user_id,$order_info['price_total'],'订单支付',1,-1,$order_id);
+                    // 支付完成后回调
+                    $back_res = OrderCallback::goodsOrderCallBack($order_info,$pay_type);
+                    if(!$back_res['ret_val']) $this->exception($back_res['msg']);
+                    $ret_data['pay_status'] = 1;
+                    break;
+
+                case 3://移动支付(支付宝)
+                    break;
+                case 4:  //4移动支付(微信)
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/customOrderNotify';
+                    $pay_config = WeChatPay::wxPay('订单支付',$pay_no,$order_info['price_total'],$notify_url,'APP',$user_info['openid']);
+                    if($pay_config['code'] != 200) $this->exception($pay_config['msg']);
+                    $ret_data['config'] = $pay_config['config'];
+                    break;
+                case 5: //pc(微信扫码)
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/customOrderNotify';
+                    $app = Factory::payment(config('app.wx_pay'));
+                    $result = $app->order->unify([
+                        'body' => '微信扫码支付',
+                        'out_trade_no' => $pay_no,
+                        'total_fee' => $order_info['price_total'] * 100,
+                        'notify_url' => $notify_url, // 支付结果通知网址,如果不设置则会使用配置里的默认地址
+                        'trade_type' => 'NATIVE', // 请对应换成你的支付方式对应的值类型
+                    ]);
+                    if(!isset($result['code_url']))$this->exception('获取微信付款码失败');
+                    $ret_data['code_url'] = $result['code_url'];
+                    break;
+                case 6: //pc(支付宝扫码)
+                    break;
+            }
+            Db::commit();
+        }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg =  $e->getMessage();
+            Db::rollback();
+        }
+        $this->transReturn($ret_data);
+    }
+
+    /**
+     * @title 确认收货
+     * @desc  确认收货
+     * @author  qc
+     * @url /api/Custom_order/confirmReceipt
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function confirmReceipt()
+    {
+        $order_id = input('post.order_id');
+        $detail = GiftOrder::where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 0) $this->error('订单未支付');
+        if($detail['status'] == 1) $this->error('订单未发货');
+        if($detail['status'] == 3) $this->error('订单已收货');
+        GiftOrder::update(['status'=>3],['id'=>$order_id]);
+        $this->success('已确认收货');
+    }
+
+    /**
+     * @title 催促发货
+     * @desc  催促发货
+     * @author  qc
+     * @url /api/Custom_order/urgeExpress
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function urgeExpress()
+    {
+        $order_id = input('post.order_id');
+        $detail = GiftOrder::where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 1) $this->error('订单状态有误');
+        $check_urge = OrderUrge::where(['order_table'=>'gift_order','order_id'=>$order_id,'day'=>date('Y-m-d')])->count();
+        if($check_urge) $this->error('今天已经催发过了...');
+        OrderUrge::create(['order_id'=>$order_id,'user_id'=>$this->user_id,'order_table'=>'gift_order','day'=>date('Y-m-d')]);
+        $this->success('催发成功');
+    }
+
+
+
+
+
+}

+ 344 - 0
application/api/controller/ExchangeOrder.php

@@ -0,0 +1,344 @@
+<?php
+namespace app\api\controller;
+use app\common\model\ExchangeGoods;
+use app\common\service\OrderCallback;
+use app\common\model\ExchangeOrder as EOM;
+use app\common\model\DeliveryAddress;
+use app\common\model\GoodsOrder;
+use app\common\model\User;
+use app\common\model\UserWallet;
+use think\Db;
+use think\Exception;
+
+/**
+ * @title 兑换订单
+ * @controller ExchangeOrder
+ * @group base
+ */
+class ExchangeOrder extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 生成订单(立即购买)
+     * @desc  立即购买场景
+     * @author  qc
+     * @url /api/Exchange_order/createOrderImmediately
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:goods_id type:int require:1  default:0 desc:商品id
+     * @param name:num type:int default:1 desc:数量
+     * @param name:add_id type:int default:1 desc:收货地址id
+     * @return name:order_id type:int default:1 desc:订单id
+     */
+    public function createOrderImmediately()
+    {
+        $goods_id = input('post.goods_id');
+        $num = input('post.num');
+        $add_id = input('post.add_id');
+        if(!$goods_id )  $this->error('请选择商品');
+        if($num <=0 ) $this->error('数量有误');
+        if(!$add_id ) $this->error('请选择收货地址');
+        Db::startTrans();
+        try {
+            // 商品详情
+            $goods_info = ExchangeGoods::where('id',$goods_id)->where('is_deleted',0)->where('status',1)->find();
+            if(!$goods_info) throw new Exception('商品已下架');
+            $goods_info = $goods_info->toArray();
+            if($goods_info['stock'] < $num) throw new Exception('库存不足');
+            $integral = UserWallet::where('user_id',$this->user_id)->value('integral');
+            $need_integral = $goods_info['integral'] * $num;
+            if($integral < $need_integral) throw new Exception('积分余额不足');
+            $add_info = DeliveryAddress::find($add_id)->toArray();
+            $price_goods = bcmul($num,$goods_info['sell_price'],2); // 需要支付价格
+            $price_express = 0; // 快递费用
+            $order_insert = [
+                'user_id' => $this->user_id,
+                'goods_id' => $goods_id,
+                'goods_name' => $goods_info['name'],
+                'goods_cover' => $goods_info['cover'],
+                'order_no' => get_order_sn(),
+                'price_total' => $price_goods +  $price_express,
+                'price_goods' => $price_goods,
+                'price_express' => $price_express,
+                'goods_num' => $num,
+                'integral' => $need_integral,
+                'pro_name' => $add_info['pro_name'],
+                'city_name' => $add_info['city_name'],
+                'county_name' => $add_info['county_name'],
+                'street_name' => $add_info['street_name'],
+                'user_name' => $add_info['name'],
+                'add_detail' => $add_info['detail'],
+                'phone' => $add_info['phone'],
+            ];
+            $order_info = EOM::create($order_insert);
+            ExchangeGoods::where('id',$goods_id)->setDec('stock',$num);
+            if($need_integral) UserWallet::userIntegralChange($this->user_id,$need_integral,'兑换商品',1,-1,$order_info['id']);
+            Db::commit();
+        }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg = $e->getMessage();
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('添加成功',['order_id'=>$order_info->id]):$this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 兑换订单支付
+     * @desc  兑换订单支付
+     * @author  qc
+     * @url /api/Exchange_order/orderPay
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:order_id type:int require:1 default:-- desc:订单id
+     * @param name:pay_type type:int require:1 default:1 desc:支付方式1微信2余额3支付宝
+     * @return name:pay_status type:array default:0 desc:支付状态(0待支付,1支付成功,【余额支付或金额为0不需要吊起支付】直接完成订单状态)
+     * @return name:config type:array default:0 desc:支付配置
+     * @return name:config.appId type:string default:-- desc:公众账号ID(pay_type=1)
+     * @return name:config.nonceStr type:string default:-- desc:随机字符串(pay_type=1)
+     * @return name:config.signType type:string default:-- desc:签名类型(pay_type=1)
+     * @return name:config.paySign type:string default:-- desc:签名(pay_type=1)
+     * @return name:config.timestamp type:string default:-- desc:时间戳(pay_type=1)
+     */
+    public function orderPay()
+    {
+        $order_id = input('post.order_id');
+        $pay_type = input('post.pay_type',1);
+        Db::startTrans();
+        $ret_data = ['pay_status'=>0,'config'=>[]];
+        try{
+            $order_info = EOM::where('id',$order_id)->find()->toArray();
+            if($order_info['status'] !=0 ) $this->exception('订单状态有误');
+            $pay_no = $order_info['pay_no'] ?  $order_info['pay_no'] : get_order_sn();
+            EOM::where('id',$order_id)->update(['pay_no'=>$pay_no]);
+            if($order_info['price_total'] > 0) {
+                switch ($pay_type){
+                    case 1:
+                        $notify_url = $this->request->root(true) . '/api/WeChatPay/exchangeOrderNotify';
+                        $user_info = User::where('id',$this->user_id)->find()->toArray();
+                        $config = WeChatPay::wxPay('订单支付',$pay_no,$order_info['price_total'],$notify_url,'JSAPI',$user_info['openid']);
+                        if(!$config) $this->exception('获取微信支付配置失败');
+                        break;
+                    case 2:
+                        $money = UserWallet::where('user_id',$this->user_id)->value('money');
+                        if($money < $order_info['price_total']) $this->exception('佣金余额不足!');
+                        UserWallet::userMoneyChange($this->user_id,$order_info['price_total'],'佣金支付',1,-1,$order_id);
+                        $pay_res = OrderCallback::exchangeOrderCallBack($order_info,$pay_type);
+                        Db::commit();
+                        $ret_data=['pay_status'=>1,'config'=>[]];
+                        $this->ret_msg = '支付成功';
+                        break;
+                    case 3:
+                        // 支付宝支付
+                        break;
+                }
+            }else{
+               OrderCallback::exchangeOrderCallBack($order_info,$pay_type);
+               Db::commit();
+               $ret_data=['pay_status'=>1,'config'=>[]];
+               $this->ret_msg = '支付成功';
+            }
+        }catch (\Exception $e){
+            $this->ret_msg = $e->getMessage();
+            $this->is_commit = false;
+            Db::rollback();
+        }
+        $this->transReturn($ret_data);
+    }
+
+    /**
+     * @title 获取订单列表
+     * @desc 获取订单列表
+     * @author qc
+     * @method GET
+     * @url /api/Exchange_order/getOrderList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数
+     * @param  name:status type:int default:-1  desc:状态
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_name type:string default:-- desc:商品名称
+     * @return name:goods_cover type:string default:--desc:商品封面
+     * @return name:order_no type:string default:-- desc:订单号
+     * @return name:price_total type:float default:-- desc:待支付金额(含运费)
+     * @return name:price_goods type:float default:-- desc:商品金额(不含运费)
+     * @return name:price_express type:float default:-- desc:运费
+     * @return name:pay_state type:int default:0 desc:支付状态(0未支付,1已支付)
+     * @return name:pay_type type:int default:0 desc:支付方式(1微信2余额3支付宝)
+     * @return name:status type:int default:0 desc:订单状态--0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,,9取消
+     * @return name:pay_no type:string default:-- desc:支付单号
+     * @return name:pay_at type:string default:-- desc:支付时间
+     * @return name:cancel_state type:int default:-- desc:取消状态(0未取消,1已取消)
+     * @return name:express_state type:int default:-- desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_id type:int default:-- desc:快递公司id
+     * @return name:express_company_title type:string default:-- desc:发货快递公司名称
+     * @return name:express_send_no type:string default:-- desc:发货单号
+     * @return name:express_send_at type:string default:-- desc:发货时间
+     * @return name:remark type:string default:-- desc:订单备注
+     * @return name:pro_name type:string default:-- desc:收货省
+     * @return name:city_name type:string default:-- desc:收货市
+     * @return name:county_name type:string default:-- desc:收货区
+     * @return name:street_name type:string default:-- desc:收货街道(乡镇)
+     * @return name:add_detail type:string default:-- desc:收货详细地址
+     * @return name:user_name type:string default:-- desc:收货人
+     * @return name:phone type:string default:-- desc:收货人电话
+     */
+    public function getOrderList()
+    {
+        $status = input('get.status',-1);
+        $where = [];
+        $where[] = ['user_id','=',$this->user_id];
+        if($status > -1) $where[] = ['status','=',$status];
+        $list = EOM::where($where)->order('id desc ')->limit($this->off_set,$this->page_num)->select()->toArray();
+        $this->success('',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取订单详情
+     * @desc 获取订单详情
+     * @author qc
+     * @method GET
+     * @url /api/Exchange_order/getOrderDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int default:--  desc:订单id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_name type:string default:-- desc:商品名称
+     * @return name:goods_cover type:string default:--desc:商品封面
+     * @return name:order_no type:string default:-- desc:订单号
+     * @return name:price_total type:float default:-- desc:待支付金额(含运费)
+     * @return name:price_goods type:float default:-- desc:商品金额(不含运费)
+     * @return name:price_express type:float default:-- desc:运费
+     * @return name:pay_state type:int default:0 desc:支付状态(0未支付,1已支付)
+     * @return name:pay_type type:int default:0 desc:支付方式(1微信2余额3支付宝)
+     * @return name:status type:int default:0 desc:订单状态--0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,,9取消
+     * @return name:pay_no type:string default:-- desc:支付单号
+     * @return name:pay_at type:string default:-- desc:支付时间
+     * @return name:cancel_state type:int default:-- desc:取消状态(0未取消,1已取消)
+     * @return name:express_state type:int default:-- desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_id type:int default:-- desc:快递公司id
+     * @return name:express_company_title type:string default:-- desc:发货快递公司名称
+     * @return name:express_send_no type:string default:-- desc:发货单号
+     * @return name:express_send_at type:string default:-- desc:发货时间
+     * @return name:remark type:string default:-- desc:订单备注
+     * @return name:pro_name type:string default:-- desc:收货省
+     * @return name:city_name type:string default:-- desc:收货市
+     * @return name:county_name type:string default:-- desc:收货区
+     * @return name:street_name type:string default:-- desc:收货街道(乡镇)
+     * @return name:add_detail type:string default:-- desc:收货详细地址
+     * @return name:user_name type:string default:-- desc:收货人
+     * @return name:phone type:string default:-- desc:收货人电话
+     */
+    public function getOrderDetail()
+    {
+        $order_id = input('get.order_id');
+        $detail = EOM::where('id',$order_id)->find()->toArray();
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 取消订单
+     * @desc  取消订单
+     * @author  qc
+     * @url /api/Exchange_order/cancelOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function cancelOrder()
+    {
+        $order_id = input('post.order_id');
+        Db::startTrans();
+        try {
+            $detail = EOM::where('id',$order_id)->find()->toArray();
+            if($detail['status'] != 0) $this->exception('订单状态有误');
+            // 商品库存
+            ExchangeGoods::where('id',$detail['goods_id'])->setInc('stock',$detail['goods_num']);
+            // 取消订单状态
+            GoodsOrder::update(['status'=>9],['id'=>$order_id]);
+            // 积分退回
+            if($detail['integral']) UserWallet::userIntegralChange($detail['user_id'],$detail['integral'],'订单取消退回',2,1,$order_id);
+            Db::commit();
+        }catch (\Exception $e){
+            $this->ret_msg = $e->getMessage();
+            $this->is_commit = false;
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('取消成功') : $this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 删除订单
+     * @desc  删除订单
+     * @author  qc
+     * @url /api/Exchange_order/deleteOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function deleteOrder()
+    {
+        $order_id = input('post.order_id');
+        $detail = EOM::where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 0) $this->error('请先取消订单');
+        GoodsOrder::update(['is_deleted'=>1],['id'=>$order_id]);
+        $this->success('删除成功');
+    }
+
+    /**
+     * @title 更换订单收货地址
+     * @desc  更换订单收货地址(仅待支付订单可以修改地址)
+     * @author  qc
+     * @url /api/Exchange_order/changeOrderDelivery
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:add_id type:int require:1  default:0 desc:收货地址id
+     */
+    public function changeOrderDelivery()
+    {
+        $order_id = input('post.order_id');
+        $add_id = input('post.add_id');
+        $detail = EOM::where('id',$order_id)->find()->toArray();
+        if($detail['status'] != 0) $this->error('操作错误');
+        $add_info = DeliveryAddress::find($add_id)->toArray();
+        $order_update =[
+            'pro_name' => $add_info['pro_name'],
+            'city_name' => $add_info['city_name'],
+            'county_name' => $add_info['county_name'],
+            'street_name' => $add_info['street_name'],
+            'add_detail' => $add_info['detail'],
+            'user_name' => $add_info['name'],
+            'phone' => $add_info['phone'],
+        ];
+        EOM::update($order_update,['id'=>$order_id]);
+        $this->success('修改成功');
+
+    }
+
+    /**
+     * @title 确认收货
+     * @desc  确认收货
+     * @author  qc
+     * @url /api/Exchange_order/confirmReceipt
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function confirmReceipt()
+    {
+        $order_id = input('post.order_id');
+        $detail =EOM::where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 0) $this->error('订单未支付');
+        if($detail['status'] == 1) $this->error('订单未发货');
+        if($detail['status'] == 3) $this->error('订单已收货');
+        EOM::update(['status'=>3],['id'=>$order_id]);
+        $this->success('已确认收货');
+    }
+
+
+
+}

+ 607 - 0
application/api/controller/Expedite.php

@@ -0,0 +1,607 @@
+<?php
+
+
+namespace app\api\controller;
+use AlibabaCloud\Client\AlibabaCloud;
+use AlibabaCloud\Client\Exception\ClientException;
+use AlibabaCloud\Client\Exception\ServerException;
+use app\common\model\CouponConfig;
+use app\common\model\ExchangeGoods;
+use app\common\model\GoodsCate;
+use app\common\model\GoodsSeason;
+use app\common\model\GoodsSellInfo;
+use app\common\model\GoodsServe;
+use app\common\model\GoodsTerritory;
+use app\common\model\MallMenu;
+use app\common\model\OrderComment;
+use app\common\model\ReductionActivity;
+use app\common\model\RemarkLabel;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\TopSearch;
+use app\common\model\UserCollect;
+use app\common\model\UserTrack;
+use app\common\service\Activity;
+use think\Db;
+/**
+ * @title 不需要验证token接口(商品列表等)
+ * @controller Expedite
+ * @package app\api\controller
+ */
+class Expedite extends Base
+{
+
+    public function initialize(){
+        parent::initialize();
+        parent::setUid();
+    }
+
+
+    /**
+     * @title 获取首页轮播图(广告位)
+     * @desc  获取首页轮播图(广告位)
+     * @author  qc
+     * @url /api/Expedite/getBanner
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:place type:int  default:1 desc:展示位置1商城首页2营养百科3视频专栏4商城商品5商城活动6商城分类7商城广告8预售
+     * @param  name:num type:int  default:5 desc:查询数量
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:link type:srting default:-- desc:链接
+     */
+    public function getBanner()
+    {
+        $num = input('get.num',5);
+        $place = input('get.place',1);
+        $list =  Db::name('store_banner')
+            ->field('id,cover,link')
+            ->where(['is_deleted'=>0,'place'=>$place])
+            ->limit(0,$num)
+            ->order('sort desc ,id desc')
+            ->select();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取首页小菜单
+     * @desc  获取首页小菜单
+     * @author  qc
+     * @url /api/Expedite/getIndexMenu
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int  default:5 desc:查询数量
+     * @return name:logo type:srting default:-- desc:图片路径
+     * @return name:link type:srting default:-- desc:跳转链接
+     */
+    public function getIndexMenu()
+    {
+        $list = MallMenu::where('is_deleted',0)->where('pid',0)->select()->toArray();
+        $this->success('ok',$list);
+    }
+
+    /**
+     * @title 获取商品分类(四级)
+     * @desc  获取商品分类(四级)
+     * @author  qc
+     * @url /api/Expedite/getGoodsCate
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:logo type:srting default:-- desc:图片路径
+     * @return name:lev type:srting default:-- desc:分类等级(1,2,3,4)
+     * @return name:children type:array default:-- desc:下级分类(数据同上)
+     */
+    public function getGoodsCate()
+    {
+        $list = GoodsCate::getCateTree();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取商品第一级分类
+     * @desc  获取商品第一级分类
+     * @author  qc
+     * @url /api/Expedite/getFirstClassify
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:logo type:srting default:-- desc:图片路径
+     * @return name:lev type:srting default:-- desc:分类等级
+     */
+    public function getFirstClassify()
+    {
+        $list = GoodsCate::field('id,title,logo,lev')->where('lev',1)->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 获取商品时令设置(二级)
+     * @desc  获取商品时令设置(二级)
+     * @author  qc
+     * @url /api/Expedite/getGoodsSeason
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:lev type:srting default:-- desc:分类等级(1,2)
+     * @return name:children type:array default:-- desc:下级分类(数据同上)
+     */
+    public function getGoodsSeason()
+    {
+        $list = GoodsSeason::getSeasonTree();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取商品地域设置(二级)
+     * @desc  获取商品地域设置(二级)
+     * @author  qc
+     * @url /api/Expedite/getGoodsTerritory
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:lev type:srting default:-- desc:分类等级(1,2)
+     * @return name:children type:array default:-- desc:下级分类(数据同上)
+     */
+    public function getGoodsTerritory()
+    {
+        $list = GoodsTerritory::getTerritoryTree();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 获取商品列表
+     * @desc  获取商品列表
+     * @author  qc
+     * @url /api/Expedite/getGoodsList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数
+     * @param  name:goods_name type:string require:0  default:-- desc:商品名称
+     * @param  name:first_classify type:int require:0  default:-- desc:一级分类id
+     * @param  name:second_classify type:int require:0  default:-- desc:二级分类id
+     * @param  name:third_classify type:int require:0  default:-- desc:三级分类id
+     * @param  name:fourth_classify type:int require:0  default:-- desc:四级分类id
+     * @param  name:is_presell type:int require:0  default:0 desc:是否是预售(0否1是)
+     * @param  name:first_season type:int require:0  default:-- desc:第一级时令id
+     * @param  name:second_season type:int require:0  default:-- desc:第二级时令id
+     * @param  name:first_territory type:int require:0  default:-- desc:第一级地域id
+     * @param  name:second_territory type:int require:0  default:-- desc:第二级地域id
+     * @param  name:column_id type:int require:0  default:-- desc:推荐专栏id
+     * @param  name:is_zx type:int require:0  default:-1 desc:是否是产地直销(-1全部,0否,1是)
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面图
+     * @return name:desc type:string default:-- desc:商品简述(副标题)
+     * @return name:low_price type:float default:-- desc:最低售价
+     * @return name:low_original type:float default:-- desc:最低原价格
+     * @return name:total_num type:int default:-- desc:商品总数量
+     * @return name:detail type:int default:-- desc:商品详情
+     * @return name:first_classify type:int require:0  default:-- desc:一级分类id
+     * @return name:second_classify type:int require:0  default:-- desc:二级分类id
+     * @return name:third_classify type:int require:0  default:-- desc:三级分类id
+     * @return name:fourth_classify type:int require:0  default:-- desc:四级分类id
+     * @return name:freight_type type:int default:-- desc:运费类型0固定金额,1运费模板
+     * @return name:freight_id type:int default:-- desc:模板id(freight_type=1)
+     * @return name:postage type:float default:-- desc:运费(freight_type=0)
+     * @return name:share_money type:float default:-- desc:分享返利金额
+     * @return name:source_pic type:string default:-- desc:商品溯源图(多张)
+     * @return name:goods_match type:string default:-- desc:商品搭配推荐(多个用|隔开)
+     * @return name:item_list type:array default:-- desc:商品多规格列表
+     * @return name:item_list.spec_info type:array default:-- desc:规格型号设置['规格组id'=>'规格id','规格组id'=>'规格id'];
+     * @return name:item_list.goods_no type:string default:-- desc:规格货号
+     * @return name:item_list.goods_title:string default:-- desc:规格标题
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.stock type:int default:-- desc:剩余库存
+     * @return name:item_list.original_price type:float default:-- desc:原价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     * @return name:first_classify_name type:int require:0  default:-- desc:一级分类名
+     * @return name:second_classify_name type:int require:0  default:-- desc:二级分类名
+     * @return name:third_classify_name type:int require:0  default:-- desc:三级分类名
+     * @return name:fourth_classify_name type:int require:0  default:-- desc:四级分类名
+     * @return name:is_presell type:int require:0  default:-- desc:是否是预售商品(0否1是)
+     * @return name:sell_time type:string require:0  default:-- desc:预售时间
+     * @return name:first_season type:int require:0  default:0 desc:第一级时令id
+     * @return name:second_season type:int require:0  default:0 desc:第二级时令id
+     * @return name:first_territory type:int require:0  default:0 desc:第一级地域id
+     * @return name:second_territory type:int require:0  default:0 desc:第二级地域id
+     * @return name:first_season_name type:string require:0  default:0 desc:第一级时令名称
+     * @return name:second_season_name type:string require:0  default:0 desc:第二级时令名称
+     * @return name:first_territory_name type:string require:0  default:0 desc:第一级地域名称
+     * @return name:second_territory_name type:string require:0  default:0 desc:第二级地域名称
+     */
+    public function getGoodsList(){
+        $all_cate = GoodsCate::field('id,title')->select()->toArray();
+        $all_cate = array_column($all_cate,null,'id');
+        $all_season = GoodsSeason::field('id,title')->select()->toArray();
+        $all_season = array_column($all_season,null,'id');
+        $all_territory= GoodsTerritory::field('id,title')->select()->toArray();
+        $all_territory = array_column($all_territory,null,'id');
+        $input = input('get.');
+        $sel_where = [];
+        $sel_where[] = ['status','=',1];
+        $sel_where[] = ['is_deleted','=',0];
+        if(isset_full($input,'goods_name'))$sel_where[] = ['name','like',"%".$input['goods_name']."%"];
+        if(isset_full($input,'first_classify'))$sel_where[] = ['first_classify','=',$input['first_classify']];
+        if(isset_full($input,'second_classify'))$sel_where[] = ['second_classify','=',$input['second_classify']];
+        if(isset_full($input,'third_classify'))$sel_where[] = ['third_classify','=',$input['third_classify']];
+        if(isset_full($input,'fourth_classify'))$sel_where[] = ['fourth_classify','=',$input['fourth_classify']];
+        if(isset_full($input,'first_season'))$sel_where[] = ['first_season','=',$input['first_season']];
+        if(isset_full($input,'second_season'))$sel_where[] = ['second_season','=',$input['second_season']];
+        if(isset_full($input,'first_territory'))$sel_where[] = ['first_territory','=',$input['first_territory']];
+        if(isset_full($input,'second_territory'))$sel_where[] = ['second_territory','=',$input['second_territory']];
+        if(isset_full($input,'column_id'))$sel_where[] = ['column_id','=',$input['column_id']];
+        if(isset($input['is_zx']) && $input['is_zx'] >=0 ) $sel_where[] = ['is_zx','=',$input['is_zx']];
+        if(isset_full($input,'is_presell')){
+            $sel_where[] = ['is_presell','=',$input['is_presell']];
+        }else{
+            $sel_where[] = ['is_presell','=',0];
+        }
+        $list = StoreGoods::with(['itemList'])->where($sel_where)->limit($this->off_set,$this->page_num)->select()->toArray();
+        foreach ($list as &$v){
+            $v['first_classify_name'] = isset($all_cate[$v['first_classify']]['title']) ? $all_cate[$v['first_classify']]['title']:'';
+            $v['second_classify_name'] = isset($all_cate[$v['second_classify']]['title']) ? $all_cate[$v['second_classify']]['title']:'';
+            $v['third_classify_name'] = isset($all_cate[$v['third_classify']]['title']) ? $all_cate[$v['third_classify']]['title']:'';
+            $v['fourth_classify_name'] = isset($all_cate[$v['fourth_classify']]['title']) ?$all_cate[$v['fourth_classify']]['title']:'';
+            $v['low_original'] = min(array_column($v['item_list'],'original_price'));
+            $v['low_price'] = min(array_column($v['item_list'],'sell_price'));
+            $v['first_season_name'] =  isset($all_season[$v['first_season']]['title']) ? $all_season[$v['first_season']]['title']:'';
+            $v['second_season_name'] =  isset($all_season[$v['second_season']]['title']) ? $all_season[$v['second_season']]['title']:'';
+            $v['first_territory_name'] =  isset($all_territory[$v['first_territory']]['title']) ? $all_territory[$v['first_territory']]['title']:'';
+            $v['second_territory_name'] =  isset($all_territory[$v['second_territory']]['title']) ? $all_territory[$v['second_territory']]['title']:'';
+            $v['total_num'] = array_sum(array_column($v['item_list'],'base_stock'));
+        }
+        $this->success('ok',['list'=>$list]);
+
+    }
+
+    /**
+     * @title 获取商品详情
+     * @desc  获取商品详情
+     * @author  qc
+     * @url /api/Expedite/getGoodsDetail
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:goods_id  type:int require:1  default:0 desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面图
+     * @return name:desc type:string default:-- desc:商品简述(副标题)
+     * @return name:low_price type:float default:-- desc:最低价格
+     * @return name:max_price type:float default:-- desc:最高价格(下划线公用)
+     * @return name:low_seckill type:float default:-- desc:最低秒杀价格(有秒杀活动)
+     * @return name:low_group type:float default:-- desc:最低拼团价格(有拼团活动)
+     * @return name:low_discount type:float default:-- desc:最低折扣价格(有折扣活动)
+     * @return name:discount type:float default:-- desc:商品折扣(没有折扣为10,有折扣活动,例如75折,值为7.5)
+     * @return name:freight_type type:int default:-- desc:运费类型0固定金额,1运费模板
+     * @return name:freight_id type:int default:-- desc:模板id(freight_type=1)
+     * @return name:postage type:float default:-- desc:运费(freight_type=0)
+     * @return name:is_collect type:int default:-- desc:是否收藏(1是0否)
+     * @return name:effect type:string default:-- desc:商品功效(多个用|隔开)
+     * @return name:explain type:string default:-- desc:商品说明(使用说明)
+     * @return name:share_money type:float default:-- desc:分享返利金额
+     * @return name:source_pic type:string default:-- desc:商品溯源图(多张)
+     * @return name:goods_match type:string default:-- desc:商品搭配推荐(多个用|隔开)
+     * @return name:remark_title type:array default:-- desc:评论标签(数组)
+     * @return name:serve_title type:array default:-- desc:服务标签(数组)
+     * @return name:is_presell type:int require:0  default:-- desc:是否是预售商品(0否1是,预售商品不加购物)
+     * @return name:sell_time type:string require:0  default:-- desc:预售时间
+     * @return name:first_season type:int require:0  default:0 desc:第一级时令id
+     * @return name:second_season type:int require:0  default:0 desc:第二级时令id
+     * @return name:first_territory type:int require:0  default:0 desc:第一级地域id
+     * @return name:second_territory type:int require:0  default:0 desc:第二级地域id
+     * @return name:first_season_name type:string require:0  default:0 desc:第一级时令名称
+     * @return name:second_season_name type:string require:0  default:0 desc:第二级时令名称
+     * @return name:first_territory_name type:string require:0  default:0 desc:第一级地域名称
+     * @return name:second_territory_name type:string require:0  default:0 desc:第二级地域名称
+     * @return name:item_list type:array default:-- desc:商品多规格列表
+     * @return name:item_list.spec_info type:array default:-- desc:规格型号设置;
+     * @return name:item_list.goods_no type:string default:-- desc:规格货号
+     * @return name:item_list.goods_title:string default:-- desc:规格标题
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.stock type:int default:-- desc:剩余库存
+     * @return name:item_list.original_price type:float default:-- desc:原价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     * @return name:item_list.seckill_price type:float default:-- desc:秒杀价(没有秒杀活动则=售价)
+     * @return name:goods_param type:array default:-- desc:商品相关参数
+     * @return name:goods_param.title type:string default:-- desc:参数名
+     * @return name:goods_param.value type:string default:-- desc:参数值
+     * @return name:seckill type:array default:-- desc:秒杀活动详情(为空:商品没有正在进行的秒杀活动)
+     * @return name:seckill.start_time type:string default:-- desc:开始时间
+     * @return name:seckill.end_time type:string default:-- desc:结束时间
+     * @return name:group type:array default:-- desc:拼团活动
+     * @return name:group.start_time type:string default:-- desc:开始时间
+     * @return name:group.end_time type:string default:-- desc:结束时间
+     * @return name:group.full_num type:int default:-- desc:成团人数
+     * @return name:discount_act type:array default:-- desc:折扣活动
+     * @return name:discount_act.id type:int default:-- desc:折扣活动id
+     * @return name:reduction type:array default:-- desc:满减活动
+     * @return name:reduction.id type:int default:-- desc:满减活动id
+     * @return name:reduction.title type:string default:-- desc:满减标题
+     * @return name:reduction.start_time type:string default:-- desc:满减开始时间
+     * @return name:reduction.end_time type:string default:-- desc:满减结束时间
+     * @return name:reduction.act_set type:array default:-- desc:满减设置
+     * @return name:reduction.act_set.full type:float default:-- desc:满多少
+     * @return name:reduction.act_set.reduction type:float default:-- desc:减多少
+     *
+     */
+    public function getGoodsDetail()
+    {
+        $goods_id = input('goods_id');
+        if($this->user_id)UserTrack::createTrack($this->user_id,1,$goods_id);
+        $detail = StoreGoods::with(['itemList'])->field('g.*,p.goods_param')->alias('g')->leftJoin('GoodsParam p','g.id = p.goods_id')->where('g.id',$goods_id)->find()->toArray();
+        if(isset($detail['goods_param']) && !empty($detail['goods_param'])) $detail['goods_param'] = json_decode($detail['goods_param'],true);
+        $detail['max_price'] = max(array_column($detail['item_list'],'original_price'));
+        $detail['remark_title'] = RemarkLabel::getRemarkLabelTitle($detail['remark_label']);
+        $detail['serve_title'] = GoodsServe::getServeLabelTitle($detail['serve_label']);
+        $detail['first_season_name']  ='';
+        $detail['first_season_name']  ='';
+        $detail['first_territory_name']  ='';
+        $detail['first_season_name']  ='';
+        if($detail['first_season']) $detail['first_season_name'] = GoodsSeason::where('id',$detail['first_season'])->value('title');
+        if($detail['second_season']) $detail['second_season_name'] = GoodsSeason::where('id',$detail['second_season'])->value('title');
+        if($detail['first_territory']) $detail['first_territory_name'] = GoodsTerritory::where('id',$detail['first_territory'])->value('title');
+        if($detail['second_territory']) $detail['second_territory_name'] = GoodsTerritory::where('id',$detail['second_territory'])->value('title');
+        $goods_act = Activity::goodsActivityList($goods_id);
+        $detail['discount'] = 10;
+        foreach ($detail['item_list'] as $ik=>&$iv)
+        {
+            $iv['seckill_price'] = $iv['sell_price'];
+            $iv['group_price'] = $iv['sell_price'];
+            $iv['discount_price'] = $iv['sell_price'];
+            // 秒杀
+            if(!empty($goods_act['seckill']['goods'])){
+                foreach ($goods_act['seckill']['goods']['item'] as $sv){
+                    if($sv['spec_id'] ==  $iv['id']){
+                        $iv['seckill_price'] = $sv['seckill_price'];
+                        break;
+                    }
+                }
+            }
+            // 拼团
+            if(!empty($goods_act['group']['goods'])){
+                foreach ($goods_act['group']['goods']['item'] as $gv){
+                    if($gv['spec_id'] ==  $iv['id']){
+                        $iv['group_price'] = $gv['group_price'];
+                        break;
+                    }
+                }
+            }
+            // 折扣活动
+            if(!empty($goods_act['discount']['act'])){
+                $detail['discount'] = bcdiv($goods_act['discount']['act']['discount'],10,1);
+                $iv['discount_price'] = bcmul($iv['sell_price'],$goods_act['discount']['act']['discount']/100,2);
+            }
+        }
+        $detail['low_seckill'] = min(array_column($detail['item_list'],'seckill_price'));
+        $detail['low_group'] = min(array_column($detail['item_list'],'group_price'));
+        $detail['low_discount'] = min(array_column($detail['item_list'],'discount_price'));
+        $detail['is_collect'] = UserCollect::checkCollectByType($this->user_id,1,$goods_id);
+        $this->success('oK',[
+            'goods_info'=>$detail,
+            'seckill'=>$goods_act['seckill']['act'],
+            'group'=>$goods_act['group']['act'],
+            'discount_act'=>$goods_act['discount']['act'],
+            'reduction'=>ReductionActivity::getAct(),
+        ]);
+    }
+
+
+    /**
+     * @title 获取商品评论
+     * @desc  获取商品评论
+     * @author  qc
+     * @url /api/Expedite/getGoodsComment
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @param  name:goods_id  type:string require:0  default:-- desc:商品名称
+     * @param  name:create_at  type:string require:0  default:-- desc:时间
+     * @param  name:spec_id  type:string require:0  default:-- desc:规格id
+     * @param  name:sort_type type:int require:0  default:-- desc:排序(1,时间,2商品评分,3物流评分,4服务评分)
+     * @param  name:order_by type:int require:0  default:2 desc:排序规则(1升序,2降序)
+     * @param  name:type type:int require:0  default:0 desc:查询类型(0全部,1有图片)
+     * @return name:spec_id type:string require:0  default:-- desc:规格id
+     * @return name:content type:string default:-- desc:内容
+     * @return name:images type:string default:-- desc:图片
+     * @return name:video type:string default:-- desc:视频
+     * @return name:goods_core type:int default:-- desc:商品评分
+     * @return name:wl_core type:int default:-- desc:物流评分
+     * @return name:serve_core type:int default:-- desc:服务评分
+     * @return name:user type:array default:-- desc:会员信息
+     * @return name:user.name type:string default:-- desc:会员名
+     * @return name:user.headimg type:string default:-- desc:会员头像
+     * @return name:total type:int default:-- desc:总评论数量
+     */
+    public function getGoodsComment()
+    {
+        $goods_id = input('get.goods_id');
+        $spec_id = input('get.spec_id');
+        $sort_type = input('get.sort_type',0);
+        $order_by = input('get.order_by',2);
+        $type = input('get.type',0);
+        $oby = $order_by == 1 ?'asc' : 'desc';
+        $where = [];
+        $where[] = ['goods_id','=',$goods_id];
+        if($spec_id)  $where[] = ['spec_id','=',$spec_id];
+        if($type)  $where[] = ['images','<>',''];
+        $sort_arr = ['id','id','goods_core','wl_core','serve_core'];
+        $total = OrderComment::where($where)->count();
+        $list = OrderComment::with('user')->where($where)
+            ->order($sort_arr[$sort_type].' '.$oby)
+            ->limit($this->off_set,$this->page_num)
+            ->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[],'total'=>$total]);
+    }
+
+
+
+
+
+    /**
+     * @title 获取平台文案设置
+     * @desc  获取平台文案设置
+     * @author  qc
+     * @url /api/Expedite/getSysConfig
+     * @method GET
+     * @param name:search_name type:string default:-- desc:根据下面名称查(不传查全部的)
+     * @return name:agreement type:string default:-- desc:用户协议
+     * @return name:about_us type:string default:-- desc:关于我们
+     * @return name:privacy type:string default:-- desc:隐私政策
+     * @return name:agent_notice type:string default:-- desc:代理商须知
+     * @return name:partner_item type:string default:-- desc:分销条款
+     * @return name:refund_desc type:string default:-- desc:退款退货说明
+     * @return name:user_equity type:string default:-- desc:会员权益
+     * @return name:integral_channel type:string default:-- desc:积分渠道
+     * @return name:sign_rule type:string default:-- desc:签到规则
+     * @return name:write_off type:string default:-- desc:注销须知
+     * @return name:customer_service type:string default:-- desc:客服设置
+     */
+    public function getSysConfig(){
+        $search_name = input('get.search_name');
+        $con_name = $search_name? [$search_name] : ['agreement','about_us','privacy','agent_notice','partner_item','refund_desc','user_equity','integral_channel','sign_rule','write_off','customer_service'];
+        $set = Db::name('system_config')->where('name','in',$con_name)->select();
+        $ret = [];
+        foreach ($set as $value) {
+            $ret[$value['name']]=$value['value'];
+        }
+        $this->success('获取成功',$ret);
+    }
+
+    /**
+     * @title 获取所有的优惠券设置
+     * @desc 获取所有的优惠券设置
+     * @author qc
+     * @method GET
+     * @url /api/Expedite/getCouponConfig
+     * @param name:goods_id type:int require:0 default:限制商品id
+     * @return name:id type:int default:-- desc:会员优惠券记录id
+     * @return name:coupon_type type:int default:-- desc:优惠券类型0全场券1商品券
+     * @return name:goods_id type:int  default:-- desc:商品id
+     * @return name:title type:int  default:-- desc:标题
+     * @return name:low_amount type:float default:-- desc:最低消费限制
+     * @return name:amount type:float default:-- desc:券额
+     * @return name:time_type type:int default:-- desc:使用时间限制0数限制(low_day)1时间限制(start_tm--end_tm)
+     * @return name:low_day type:int default:-- desc:限制天数
+     * @return name:start_tm type:string default:-- desc:开始使用时间
+     * @return name:end_tm type:string default:-- desc:结束使用时间
+     * @return name:status type:int default:-- desc:状态 (状态 0:失效 1:正常)
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:num type:int default:-- desc:优惠券总数量
+     * @return name:user_num type:int default:-- desc:每人限制领取张数0不限制
+     */
+    public function getCouponConfig()
+    {
+        $goods_id = input('get.goods_id',0);
+        $where = [];
+        $where[] = ['is_deleted','=',0];
+        $where[] = ['status','=',1];
+        if($goods_id)$where[] = ['goods_id','in',[0,$goods_id]];
+        $list = CouponConfig::where($where)->order('id desc')->select();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 发送短信验证码
+     * @desc 发送短信验证码
+     * @author qc
+     * @url /api/Expedite/sendSms
+     * @method POST
+     * @param name:phone type:int require:1 default:-- desc:要获取验证码的手机号
+     * @return name:code type:string default:-- desc:验证码
+     */
+    public function sendSms(){
+        $phone = input('post.phone');
+        if(empty($phone)) $this ->error('参数错误');
+        $code = rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9);
+        AlibabaCloud::accessKeyClient('LTAI5tEEfowhMkLu8auo6n6G', 'ch94CL3TEwNAxXNREweZl3gfk8jQ84')
+            ->regionId('cn-hangzhou')->asDefaultClient();
+        try {
+            $result = AlibabaCloud::rpc()
+                ->product('Dysmsapi')
+                ->version('2017-05-25')
+                ->action('SendSms')
+                ->method('POST')
+                ->host('dysmsapi.aliyuncs.com')
+                ->options([
+                    'query' => [
+                        'RegionId' => "cn-hangzhou",
+                        'PhoneNumbers' => $phone,
+                        'SignName' => "康养食品",
+                        'TemplateCode' => "SMS_241155218",
+                        'TemplateParam' => json_encode(array("code"=>$code)),
+                    ],
+                ])->request();
+            $result = $result->toArray();
+            if($result['Code'] == "OK") {
+                $sms_data = array(
+                    'phone'=>$phone,
+                    'code'=>$code,
+                    'result'=>$result['Message']
+                );
+                Db::name('store_member_sms')->insert($sms_data);
+                $this->success('发送成功',$code);
+            }else{
+                $this->error('发送失败');
+            }
+        } catch (ClientException $e) {
+            $this->error($e->getErrorMessage() . PHP_EOL);
+        } catch (ServerException $e) {
+            $this->error($e->getErrorMessage() . PHP_EOL);
+        }
+    }
+
+
+    /**
+     * @title 获取商品热搜设置
+     * @desc  获取商品热搜设置
+     * @author  qc
+     * @url /api/Expedite/goodsTopSearch
+     * @method GET
+     * @return name:title type:string default:-- desc:标题
+     */
+    public function goodsTopSearch()
+    {
+        $list = TopSearch::field('id,title')->where(['status'=>1,'is_deleted'=>0])->order('sort desc,id desc')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 获取热销商品
+     * @desc  获取热销商品
+     * @author  qc
+     * @url /api/Expedite/getHotSell
+     * @method GET
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名
+     * @return name:cover type:string default:-- desc:商品图片
+     * @return name:low_price type:float default:-- desc:最低价
+     * @return name:line_money type:float default:-- desc:下划线价格
+     */
+    public function getHotSell()
+    {
+        $sel_time  =  date('Y-m-d H:i:s',strtotime('-70 days'));
+        $list = GoodsSellInfo::field('i.goods_id,sum(i.num) total_num,g.name,g.cover,g.low_price')->where('i.create_at','> time',$sel_time)
+            ->alias('i')
+            ->leftJoin('StoreGoods g','g.id = i.goods_id')
+            ->group('i.goods_id')
+            ->order('total_num desc')
+            ->limit(0,20)
+            ->select()->toArray();
+        array_walk($list,function (&$v){
+            $v['line_money'] = StoreGoodsItem::where(['goods_id'=>$v['goods_id']])->max('original_price');
+        });
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+}

+ 199 - 0
application/api/controller/General.php

@@ -0,0 +1,199 @@
+<?php
+namespace app\api\controller;
+use AlibabaCloud\Client\AlibabaCloud;
+use AlibabaCloud\Client\Exception\ClientException;
+use AlibabaCloud\Client\Exception\ServerException;
+use AliPay\Scan;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\User;
+use app\common\model\UserMessage;
+use app\common\model\UserTrack;
+use think\Db;
+use think\Exception;
+use EasyWeChat\Factory;
+use function AlibabaCloud\Client\value;
+
+/**
+ * @title 其他接口
+ * @controller General
+ * @group base
+ */
+class General extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 发送短信验证码
+     * @desc 发送短信验证码
+     * @author qc
+     * @url /api/General/sendSms
+     * @method POST
+     * @tag 短信验证码
+     * @param name:phone type:int require:1 default:-- desc:要获取验证码的手机号
+     * @return name:code type:string default:-- desc:验证码
+     */
+    public function sendSms(){
+        $phone = input('post.phone');
+        if(empty($phone)) $this ->error('参数错误');
+        $code = rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9).rand(0,9);
+        AlibabaCloud::accessKeyClient('LTAI5tEEfowhMkLu8auo6n6G', 'ch94CL3TEwNAxXNREweZl3gfk8jQ84')
+            ->regionId('cn-hangzhou')->asDefaultClient();
+        try {
+            $result = AlibabaCloud::rpc()
+                ->product('Dysmsapi')
+                ->version('2017-05-25')
+                ->action('SendSms')
+                ->method('POST')
+                ->host('dysmsapi.aliyuncs.com')
+                ->options([
+                    'query' => [
+                        'RegionId' => "cn-hangzhou",
+                        'PhoneNumbers' => $phone,
+                        'SignName' => "康养食品",
+                        'TemplateCode' => "SMS_241155218",
+                        'TemplateParam' => json_encode(array("code"=>$code)),
+                    ],
+                ])->request();
+            $result = $result->toArray();
+            if($result['Code'] == "OK") {
+                $sms_data = array(
+                    'phone'=>$phone,
+                    'code'=>$code,
+                    'result'=>$result['Message']
+                );
+                Db::name('store_member_sms')->insert($sms_data);
+                $this->success('发送成功',$code);
+            }else{
+                $this->error('发送失败');
+            }
+        } catch (ClientException $e) {
+            echo $e->getErrorMessage() . PHP_EOL;
+        } catch (ServerException $e) {
+            echo $e->getErrorMessage() . PHP_EOL;
+        }
+
+    }
+
+
+    /**
+     * @title 获取物流详情
+     * @desc 获取物流详情
+     * @author qc
+     * @url /api/General/deliveryDetails
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:send_no type:string require:1 default:-- desc:物流单号(订单express_send_no字段)
+     * @return name:number type:string default:-- desc:单号
+     * @return name:type type:string default:-- desc:快递类型
+     * @return name:list type:array default:-- desc:数据列表
+     * @return name:list.time type:string default:-- desc:时间
+     * @return name:list.status type:string default:-- desc:内容
+     * @return name:deliverystatus type:int default:-- desc:0:快递收件(揽件)1.在途中2.正在派件3.已签收4.派送失败5.疑难件6.退件签收
+     * @return name:issign type:int default:-- desc:是否签收(1.是否签收)
+     * @return name:expName type:string default:-- desc:快递公司名称
+     * @return name:expSite type:string default:-- desc:快递公司官网
+     * @return name:expPhone type:string default:-- desc:快递公司电话
+     * @return name:courier type:string default:-- desc:快递员 或 快递站(没有则为空)
+     * @return name:courierPhone type:string default:-- desc:快递员电话 (没有则为空)
+     * @return name:updateTime type:string default:-- desc:快递轨迹信息最新时间
+     * @return name:takeTime type:string default:-- desc:发货到收货消耗时长 (截止最新轨迹)
+     * @return name:logo type:string default:-- desc:快递公司LOGO
+     */
+    public function deliveryDetails(){
+        $send_no = input('get.send_no');
+        $data = get_delivery($send_no);
+        $this->success('ok',$data);
+    }
+
+    /**
+     * @title 获取足迹日历信息
+     * @desc  获取足迹日历信息
+     * @author  qc
+     * @url /api/General/getCalendar
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:num type:int default:7 desc:时间(最近几天,默认7天)
+     * @return name:day_time type:string default:-- desc:时间
+     * @return name:week_day type:string default:-- desc:周几
+     */
+    public function getCalendar()
+    {
+        $num = input('num',7);
+        $calendar = get_calendar($num);
+        $this->success('ok',['list'=>$calendar]);
+    }
+
+    /**
+     * @title 获取足迹
+     * @desc  获取足迹
+     * @author  qc
+     * @url /api/General/getUserTrack
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:type type:int default:1 desc:查询类型1商品2资讯
+     * @param  name:day_time type:string default:-- desc:查询时间(2022-04-22)
+     * @return name:id type:int default:-- desc:足迹id
+     * @return name:rel_id type:float default:-- desc:浏览的id(商品类型是商品id,资讯类型是资讯的id)
+     * @return name:low_price type:float default:-- desc:商品最低价
+     * @return name:max_price type:float default:-- desc:商品下划线价格
+     * @return name:goods_cover type:string default:-- desc:商品封面
+     * @return name:goods_name type:string default:-- desc:商品名
+     * @return name:article_title type:string default:-- desc:资讯标题
+     * @return name:article_cover type:string default:-- desc:资讯封面
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:article_type type:int default:-- desc:资讯类型(1图文,2视频)
+     */
+    public function getUserTrack()
+    {
+        $type = input('get.type',1);
+        $day_time = input('get.day_time',date('Y-m-d'));
+        $where = [];
+        $where[] = ['t.user_id','=',$this->user_id];
+        $where[] = ['t.type','=',$type];
+        $where[] = ['t.year','=',date('Y',strtotime($day_time))];
+        $where[] = ['t.month','=',date('m',strtotime($day_time))];
+        $where[] = ['t.day','=',date('d',strtotime($day_time))];
+        if($type == 1){
+            $list = UserTrack::field('t.*,g.low_price,g.name goods_name,g.cover goods_cover')->where($where)
+                ->alias('t')
+                ->leftJoin('StoreGoods g','t.rel_id = g.id')
+                ->order('t.update_int desc')
+                ->select()->toArray();
+            foreach ($list as &$v){
+                $v['max_price'] = StoreGoodsItem::where('goods_id',$v['rel_id'])->max('original_price');
+            }
+        }else{
+            $list = UserTrack::field('t.*,i.title article_title,i.cover article_cover,i.video_url,i.type article_type,i.read_num')->where($where)
+                ->alias('t')
+                ->leftJoin('InformationArticle i','t.rel_id = i.id')
+                ->order('t.update_int desc')
+                ->select()->toArray();
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 删除足迹
+     * @desc  删除足迹
+     * @author  qc
+     * @url /api/General/delUserTrack
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:ids type:string default:-- desc:足迹id(多个用逗号隔开)
+     */
+    public function delUserTrack()
+    {
+        $ids = input('post.ids');
+        UserTrack::where('id','in',$ids)->delete();
+        $this->success('删除成功');
+    }
+
+
+
+}

+ 357 - 0
application/api/controller/Information.php

@@ -0,0 +1,357 @@
+<?php
+namespace app\api\controller;
+use app\common\model\InformationArticle;
+use app\common\model\InformationGoods;
+use app\common\model\NewsCate;
+use app\common\model\NewsChannel;
+use app\common\model\NewsMaterial;
+use app\common\model\NutritionCase;
+use app\common\model\StoreBanner;
+use app\common\model\UserCollect;
+use app\common\model\UserTrack;
+
+/**
+ * @title 资讯(康养百科)
+ * @controller Information
+ * @group base
+ */
+class Information extends Base
+{
+
+    public function initialize()
+    {
+        parent::initialize();
+        parent::setUid();
+    }
+
+    /**
+     * @title 获取分类(共两级)
+     * @desc  获取分类
+     * @author  qc
+     * @url /api/Information/getCateTree
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:logo type:string default:-- desc:图标
+     * @return name:title type:string default:0 desc:分类名称
+     * @return name:children type:array default:0 desc:下级(数据同上)
+     */
+    public function getCateTree()
+    {
+        $list = NewsCate::where(['is_deleted'=>0])->field('id,logo,title,pid,desc')->order('sort desc')->select()->toArray();
+        $list = make_tree($list);
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取二级分类
+     * @desc  获取二级分类
+     * @author  qc
+     * @url /api/Information/getSecondCate
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:pid type:int default:-- desc:一级分类id
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:logo type:string default:-- desc:图标
+     * @return name:title type:string default:0 desc:分类名称
+     * @return name:desc type:string default:0 desc:分类描述
+     */
+    public function getSecondCate()
+    {
+        $pid = input('pid');
+        $list = NewsCate::where(['is_deleted'=>0,'pid'=>$pid])->field('id,logo,title,pid,desc')->order('sort desc')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取资讯栏目
+     * @desc 获取资讯栏目
+     * @author qc
+     * @url /api/Information/getNewsChannel
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:string default:-- desc:标题
+     * @return name:desc type:string default:-- desc:描述(副标题)
+     */
+    public function getNewsChannel()
+    {
+        $list = NewsChannel::field('id,desc,title')->where(['is_deleted'=>0,'status'=>1])->order('sort desc ,id desc')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取亚健康资讯标签
+     * @desc  获取亚健康资讯标签
+     * @author  qc
+     * @url /api/Information/getNutritionCaseList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:string default:-- desc:标签名
+     * @return name:logo type:string default:-- desc:图片
+     */
+    public function getNutritionCaseList()
+    {
+        $list = NutritionCase::field('id,title,logo')->where(['status'=>1,'is_deleted'=>0])->order('sort desc ,id desc')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取亚健康资讯标签详情
+     * @desc  获取亚健康资讯标签详情
+     * @author  qc
+     * @url /api/Information/getNutritionCaseDetail
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:-- desc:标签id
+     * @return name:title type:string default:-- desc:标签名
+     * @return name:intro type:string default:-- desc:详情介绍
+     */
+    public function getNutritionCaseDetail()
+    {
+        $id= input('get.id');
+        $detail = NutritionCase::where('id',$id)->find()->toArray();
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 随机获取亚健康资讯标签
+     * @desc  随机获取
+     * @author  qc
+     * @url /api/Information/getRandNutritionCase
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:4 desc:随机数量
+     * @return name:title type:string default:-- desc:标签名
+     */
+    public function getRandNutritionCase()
+    {
+        $num = input('get.num',4);
+        $list = NutritionCase::field('id,title,logo')->where(['status'=>1,'is_deleted'=>0])->order('sort desc ,id desc')->column('title','id');
+        $rand_key = array_rand($list,$num);
+        $rand_list = [];
+        foreach ($rand_key as $key) {
+            $rand_list[] = ['id'=>$key,'title'=>$list[$key]];
+        }
+        $this->success('ok',['list'=>$rand_list]);
+    }
+
+
+    /**
+     * @title 获取资讯专题推荐商品
+     * @desc 获取资讯专题推荐商品
+     * @author qc
+     * @method GET
+     * @url /api/Information/getGoodsByNutritionCase
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:资讯id
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @return name:id type:string default:-- desc:资讯标签id
+     * @return name:news_id type:string default:-- desc:资讯id
+     * @return name:goods_set type:array default:-- desc:商品信息
+     * @return name:goods_set.name type:string default:-- desc:商品名称
+     * @return name:goods_set.desc type:float default:-- desc:商品简介(副标题)
+     * @return name:goods_set.cover type:string default:-- desc:商品封面
+     * @return name:goods_set.low_price type:float default:-- desc:最低价格
+     */
+    public function getGoodsByNutritionCase()
+    {
+        $label_id = input('get.label_id');
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        if($label_id)  $sel_where[]  = ['label','like','%'.'|'.$label_id.'|'.'%'];
+        $new_ids = InformationArticle::where('is_deleted',0)->order('id desc')->limit(0,5)->column('id');
+        $goods_ids = InformationGoods::field('goods_id,max(id) id')->where('news_id','in',$new_ids)->group('goods_id')->select()->toArray();
+        $list = InformationGoods::with('goodsSet')
+            ->where('id','in',array_column($goods_ids,'id'))
+            ->limit($this->off_set,$this->page_num)->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取轮播图
+     * @desc  获取轮播图
+     * @author  qc
+     * @url /api/Information/getBanner
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int  default:5 desc:查询数量
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:link type:srting default:-- desc:链接
+     */
+    public function getBanner()
+    {
+        $num = input('get.num',5);
+        $list =  StoreBanner::where(['place'=>2,'is_deleted'=>0])
+            ->field('id,cover,link')
+            ->limit(0,$num)
+            ->order('sort desc ,id desc')
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取资讯列表
+     * @desc
+     * @author qc
+     * @method GET
+     * @url /api/Information/getInformationList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @param  name:title type:string default:-- desc:标题
+     * @param  name:type type:int default:0 desc:类型(0全部,1图文,2视频)
+     * @param  name:channel_id type:int default:0 desc:资讯栏目id
+     * @param  name:first_classify type:int default:0 desc:一级分类
+     * @param  name:second_classify type:int default:0 desc:二级分类
+     * @param  name:is_top type:int default:0 desc:置顶查询传1(置顶文章查询)
+     * @param  name:label_id type:int default:0 desc:标签id(亚健康资讯)
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return  name:channel_id type:int default:0 desc:资讯栏目id
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:detail type:string default:-- desc:详情(视频没有这个)
+     * @return name:first_classify type:int default:-- desc:一级分类(/api/Information/getCateTree这个接口返回的第一级id)
+     * @return name:second_classify type:int default:-- desc:二级分类(/api/Information/getCateTree这个接口返回的第二级id)
+     * @return name:type type:string default:-- desc:1图文2视频
+     * @return name:is_top type:int default:-- desc:是否置顶(0否,1是)
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:is_collect type:int default:-- desc:是否收藏
+     * @return name:collect_num type:int default:-- desc:收藏量
+     * @return name:is_hot type:int default:-- desc:是否热门(0否,1是)
+     * @return name:is_new type:int default:-- desc:是否是最新(0否,1是)
+     */
+    public function getInformationList()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $title = input('get.title');
+        $type = input('get.type');
+        $is_top = input('get.is_top');
+        $channel_id = input('get.channel_id');
+        $first_classify = input('get.first_classify');
+        $second_classify = input('get.second_classify');
+        $label_id = input('get.label_id');
+        if($title)  $sel_where[]  = ['title','like','%'.$title.'%'];
+        if($type)  $sel_where[]  = ['type','=',$type];
+        if($first_classify)  $sel_where[]  = ['first_classify','=',$first_classify];
+        if($second_classify)  $sel_where[]  = ['second_classify','=',$second_classify];
+        if($is_top)  $sel_where[]  = ['is_top','=',$is_top];
+        if($channel_id)  $sel_where[]  = ['channel_id','=',$channel_id];
+        if($label_id)  $sel_where[]  = ['label','like','%'.'|'.$label_id.'|'.'%'];
+        $new_ids = InformationArticle::order('id desc')->limit(0,3)->column('id');
+        $list = InformationArticle::where($sel_where)
+            ->order('is_top desc,sort desc ,id desc')
+            ->limit($this->off_set,$this->page)->select()->toArray();
+        array_walk($list,function (&$v,$k)use ($new_ids){
+            $v['is_collect'] = UserCollect::checkCollectByType($this->user_id,2,$v['id']);
+            $v['is_new'] = in_array($v['id'],$new_ids)? 1 :0;
+            $v['collect_num'] = UserCollect::where(['coll_type'=>2,'coll_id'=>$v['id']])->count();
+            $v['is_hot'] = $v['collect_num'] > 10000 ? 1:0;
+        });
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取资讯详情
+     * @desc 获取资讯详情
+     * @author qc
+     * @method GET
+     * @url /api/Information/getInformationDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:资讯id
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:detail type:string default:-- desc:详情(视频没有这个)
+     * @return name:first_classify type:int default:-- desc:一级分类
+     * @return name:second_classify type:int default:-- desc:二级分类
+     * @return name:type type:string default:-- desc:1图文2视频
+     * @return name:is_top type:int default:-- desc:是否置顶(0否,1是)
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:is_collect type:int default:-- desc:是否收藏(0否,1是)
+     * @return name:collect_num type:int default:-- desc:收藏量
+     * @return name:is_hot type:int default:-- desc:是否热门(0否,1是)
+     * @return name:label type:int default:-- desc:亚健康标签id串(格式:|id|id|)
+     * @return name:label_name type:array default:-- desc:亚健康标签
+     * @return name:label_name.title type:array default:-- desc:亚健康标签名
+     * @return name:platform_name type:string default:-- desc:平台名称
+     */
+    public function getInformationDetail()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $sel_where[]  = ['id','=',input('get.id')];
+        if($this->user_id)UserTrack::createTrack($this->user_id,2,input('get.id'));
+        $detail = InformationArticle::where($sel_where)
+            ->order('is_top desc,sort desc ,id desc')->find();
+        if(!$detail)$this->error('该资讯已下线');
+        $detail['is_collect'] = UserCollect::checkCollectByType($this->user_id,2,$detail->id);
+        $detail['collect_num'] = UserCollect::where(['coll_type'=>2,'coll_id'=>$detail->id])->count();
+        $detail['is_hot'] = $detail['collect_num'] > 10000 ? 1:0;
+        $detail['label_name'] = [];
+        if($detail['label']){
+            $label_id =  explode('|',trim($detail['label'],'|'));
+            $detail['label_name'] = NutritionCase::field('id,title')->where('id','in',$label_id)->select()->toArray();
+        }
+        $detail['platform_name'] = config('text.platform_name');
+        InformationArticle::where('id',input('get.id'))->setInc('read_num');//阅读量+1
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 获取资讯相关商品
+     * @desc 获取资讯相关商品
+     * @author qc
+     * @method GET
+     * @url /api/Information/getInformationGoods
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:资讯id
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @return name:id type:string default:-- desc:资讯相关商品记录id
+     * @return name:news_id type:string default:-- desc:资讯id
+     * @return name:goods_set type:array default:-- desc:商品信息
+     * @return name:goods_set.name type:string default:-- desc:商品名称
+     * @return name:goods_set.desc type:float default:-- desc:商品简介(副标题)
+     * @return name:goods_set.cover type:string default:-- desc:商品封面
+     * @return name:goods_set.low_price type:float default:-- desc:最低价格
+     */
+    public function getInformationGoods()
+    {
+        $id = input('get.id');
+        $list = InformationGoods::with('goodsSet')->where(['news_id'=>$id])->limit($this->off_set,$this->page_num)->select();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+    /**
+     * @title 获取资讯素材
+     * @desc 获取资讯素材
+     * @author qc
+     * @method GET
+     * @url /api/Information/getNewsMaterial
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @param  name:type type:int default:1 desc:类型(1线上,2线下)
+     * @return name:id type:int default:-- desc:素材id
+     * @return name:type type:int default:-- desc:类型(1线上,2线下)
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:图片
+     */
+    public function  getNewsMaterial()
+    {
+        $type = input('get.type',1);
+        $list = NewsMaterial::field('id,title,type,cover')->where(['type'=>$type,'is_deleted'=>0,'status'=>1])->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+
+}

+ 443 - 0
application/api/controller/Login.php

@@ -0,0 +1,443 @@
+<?php
+namespace app\api\controller;
+use app\common\validate\UserVali;
+use app\common\model\User;
+use app\common\model\UserWallet;
+use library\service\CaptchaService;
+use library\tools\Data;
+use think\Db;
+use EasyWeChat\Factory;
+use app\common\model\InviteInfo;
+use function AlibabaCloud\Client\value;
+
+/**
+ * @title 用户登录
+ * @controller Login
+ */
+class Login extends Base
+{
+
+    /**
+     * @title 用户统一登录
+     * @desc 用户登录
+     * @author qc
+     * @url /api/Login/unifiedLogin
+     * @method POST
+     * @tag 登录 授权
+     * @param name:login_type type:int require:1 default:1 desc:登录方式(1.微信小程序,2.微信授权app,3.pc微信扫码,4.手机号验证码,5.手机号密码登录,6.qq授权app,7.pc端QQ登录)
+     * @param name:code type:int require:1 default:-- desc:code值(1)
+     * @param name:phone type:string require:0 default:0 desc:手机号(4,5)
+     * @param name:password type:string require:0 default:0 desc:登录密码(5)
+     * @param name:phone_code type:string require:0 default:0 desc:手机验证码(4)
+     * @param name:access_token type:string require:0 default:0 desc:access_token(2,6,7)
+     * @param name:openid type:string require:0 default:0 desc:openid(2)
+     * @return name:token type:string default:-- desc:用户登录成功后的token值(没返回token跳转绑定手机号!!!!!!!)
+     * @return name:phone type:string default:-- desc:用户绑定的手机号
+     */
+    public function unifiedLogin()
+    {
+        $code = input('post.code');
+        $headimg = input('post.headimg');
+        $name = input('post.name');
+        $access_token = input('post.access_token');
+        $openid = input('post.openid');
+        $login_type = input('post.login_type', 1);
+        $ret_data = ['code' => 200, 'token' => ''];
+        $msg = '登录成功';
+        try {
+            switch ($login_type){
+                case 1://微信小程序登录
+                    if (empty($code) || empty($headimg) || empty($name)) $this->exception('参数错误');
+                    $app = Factory::miniProgram(config('app.mini_program'));
+                    $data = $app->auth->session($code);
+                    if(empty($data['openid']) || empty($data['unionid'])) $this->exception($data['errmsg']);
+                    $member = User::field('id,openid,phone')->where('wechat_unionid', $data['unionid'])->find();
+                    if(!$member) $this->exception('请绑定手机号');
+                    if(!$member->openid) User::where('id',$member->id)->update(['openid'=>$data['openid']]);// 没有小程序openid则绑定openid
+                    $token = $this->createJwt($member->id);
+                    $ret_data['token'] =  $token;
+                    break;
+                case 2://微信授权app登录
+                    if(empty($access_token) || empty($openid)) $this->exception('缺少access_token或openid');
+                    $user_info = http_curl('https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid);
+                    if(!$user_info || empty( $user_info['unionid'])) $this->exception('获取用户微信信息有误');
+                    $member = User::field('id,app_openid,phone')->where('wechat_unionid', $user_info['unionid'])->find();
+                    if(!$member) $this->exception('请绑定手机号');
+                    if(!$member->app_openid)User::where('id',$member->id)->update(['app_openid'=>$user_info['openid']]);// 没有openid则绑定openid
+                    $token = $this->createJwt($member->id);
+                    $ret_data['token'] = $token;
+                    break;
+                case 3://pc微信扫码
+                    $res = http_curl('https://api.weixin.qq.com/sns/oauth2/access_token?appid='.config('pc_wx')['app_id'].'&secret='.config('pc_wx')['secret'].'&code='.$code.'&grant_type=authorization_code');
+                    if(!$res || !isset($res['access_token'])) $this->exception('获取access_token有误');
+                    $user_info = http_curl('https://api.weixin.qq.com/sns/userinfo?access_token='.$res['access_token'].'&openid='.$res['openid']);
+                    if(!$user_info) $this->exception('获取用户微信信息有误');
+                    $member = User::field('id,app_openid,phone')->where('wechat_unionid', $user_info['unionid'])->find();
+                    if(!$member) $this->exception('请绑定手机号');
+                    if(!$member->pc_openid)User::where('id',$member->id)->update(['pc_openid'=>$res['openid']]);// 没有openid则绑定openid
+                    $token = $this->createJwt($member->id);
+                    $ret_data['token'] = $token;
+                    break;
+                case 4:// 手机号验证码登录
+                    $phone = input('post.phone');
+                    $phone_code  = input('post.phone_code');
+                    $member =User::where('phone', $phone)->find();
+                    if(!$member) $this->exception('用户不存在,请先注册');
+                    $check_code = $this->checkPhoneCode($phone,$phone_code);
+                    if(!$check_code) $this->exception('验证码错误');
+                    $this->updatePhoneCode($check_code);
+                    $ret_data['token'] = $this->createJwt($member->id);
+                    break;
+                case 5://手机密码登录
+                    $phone = input('post.phone');
+                    $password = input('post.password');
+                    if (empty($password) || empty($phone)) $this->exception('参数错误');
+                    $member = User::where('phone', $phone)->find();
+                    if(!$member) $this->exception('用户不存在');
+                    if(!check_password($password,$member->encryption_password)) $this->exception('密码错误');
+                    $ret_data['token'] = $this->createJwt($member->id);
+                    break;
+                case 6://qq 授权app
+                    if(empty($access_token)) $this->error('参数错误');
+                    $res = curl_get('https://graph.qq.com/oauth2.0/me?access_token='.$access_token.'&unionid=1'.'&fmt=json');
+                    if(!$res || !isset($res['unionid'])) $this->exception('获取unionid有误');
+                    $member = User::where('qq_unionid',$res['unionid'])->find();
+                    if(!$member) $this->exception('用户不存在,请先注册');
+                    $token = $this->createJwt($member->id);
+                    $ret_data['token'] = $token;
+                    break;
+                case 7://pc QQ登录
+                    if(empty($access_token)) $this->error('参数错误');
+                    $res = curl_get('https://graph.qq.com/oauth2.0/me?access_token='.$access_token.'&unionid=1'.'&fmt=json');
+                    if(!$res || !isset($res['unionid'])) $this->exception('获取unionid有误');
+                    $member = User::where('qq_unionid',$res['unionid'])->find();
+                    if(!$member) $this->exception('用户不存在,请先注册');
+                    $token = $this->createJwt($member->id);
+                    $ret_data['token'] = $token;
+                    break;
+            }
+        }catch (\Exception $e){
+            $ret_data['code'] = 201;
+            $msg =$e->getMessage();
+        }
+        $ret_data['code'] == 200 ? $this->success($msg,$ret_data):$this->error($msg,$ret_data);
+    }
+
+
+    /**
+     * @title 账号绑定手机号
+     * @desc 账号绑定手机号
+     * @author qc
+     * @url /api/Login/accountBindPhone
+     * @method POST
+     * @param name:bind_type type:int require:1 default:1 desc:绑定类型(1.微信小程序,2.微信授权app,3.pc微信扫码,4.qq授权app,5pc授权QQ)
+     * @param name:phone type:int require:1 default:-- desc:手机号(1,2,3,4)
+     * @param name:phone_code type:string require:1 default:-- desc:手机验证码(1,2,3,4)
+     * @param name:code type:int require:0 default:-- desc:code值(1)
+     * @param name:access_token type:string require:0 default:0 desc:access_token(2,4)
+     * @param name:openid type:string require:0 default:0 desc:openid(2)
+     * @param name:pid type:string require:0 default:-- desc:推荐人(能获取到就传)
+     * @param name:name type:string require:0 default:-- desc:名称(能获取到就传)
+     * @param name:headimg type:string require:0 default:-- desc:头像(能获取到就传)
+     * @return name:token type:string default:-- desc:成功返回token
+     */
+    public function accountBindPhone()
+    {
+        $bind_type = input('post.bind_type',1);
+        $phone = input('post.phone');
+        $phone_code = input('post.phone_code');
+        $code = input('post.code');
+        $pid = input('post.pid', 0);
+        $headimgurl = input('post.headimg', '');
+        $nickname = input('post.name', '');
+        $access_token = input('post.access_token');
+        $openid = input('post.openid');
+        $check_code = $this->checkPhoneCode($phone,$phone_code);
+        if(!$check_code) $this->error('验证码错误');
+        $this->updatePhoneCode($check_code);
+        $member =User::where('phone', $phone)->find();
+        $is_new = $member ? 0:1;// 是否是新用户
+        $bind_data = [];
+        if($is_new) $bind_data['phone'] = $phone;
+        switch ($bind_type){
+            case 1://微信小程序注册
+                $app = Factory::miniProgram(config('app.mini_program'));
+                $data = $app->auth->session($code);
+                if(empty($data['openid'])) $this->error($data['errmsg']);
+                $check_member = User::where('openid',$data['openid'])->find();
+                if($check_member) $this->error('账号已存在'.$bind_type);
+                $bind_data['openid'] = $data['openid'];
+                if($is_new) $bind_data['name']   =  $nickname ? :$phone;
+                if($is_new) $bind_data['headimg'] = $headimgurl ? :'';
+                if($is_new || (!$is_new && !$member->wechat_unionid)) $bind_data['wechat_unionid'] = !empty($data['unionid']) ? $data['unionid'] :'';
+                break;
+            case 2://微信授权app注册
+                if($member && $member->app_openid) $this->error('该手机号已绑定微信'.$bind_type);
+                if(empty($access_token) || empty($openid)) $this->error('参数错误');
+                $user_info = http_curl('https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid);
+                if(!$user_info || empty($user_info['unionid'])) $this->error('获取用户微信信息有误');
+                $check_member = User::where('app_openid',$user_info['openid'])->find();
+                if($check_member) $this->error('账号已存在'.$bind_type);
+                $bind_data['app_openid'] = $user_info['openid'];
+                if($is_new) $bind_data['name']   = $user_info['nickname'];
+                if($is_new) $bind_data['headimg'] = $user_info['headimgurl'];
+                if($is_new || (!$is_new && !$member->wechat_unionid))  $bind_data['wechat_unionid'] = !empty($user_info['unionid']) ? $user_info['unionid'] :'';
+                break;
+            case 3://pc微信扫码
+                if($member && $member->pc_openid) $this->error('该手机号已绑定微信'.$bind_type);
+                if(empty($code)) $this->error('参数错误');
+                $res = http_curl('https://api.weixin.qq.com/sns/oauth2/access_token?appid='.config('pc_wx')['app_id'].'&secret='.config('pc_wx')['secret'].'&code='.$code.'&grant_type=authorization_code');
+                if(!$res || !isset($res['access_token'])) $this->error('获取access_token有误');
+                $user_info = http_curl('https://api.weixin.qq.com/sns/userinfo?access_token='.$res['access_token'].'&openid='.$res['openid']);
+                if(!$user_info) $this->error('获取用户微信信息有误');
+                $check_member = User::where('pc_openid',$user_info['openid'])->find();
+                if($check_member) $this->error('账号已存在'.$bind_type);
+                $bind_data['pc_openid'] = $user_info['openid'];
+                if($is_new) $bind_data['name']   = $user_info['nickname'];
+                if($is_new) $bind_data['headimg'] = $user_info['headimgurl'];
+                if($is_new || (!$is_new && !$member->wechat_unionid)) $bind_data['wechat_unionid'] = !empty($user_info['unionid']) ? $user_info['unionid'] :'';
+                break;
+            case 4:// qq授权app
+                if($member && $member->qq_unionid) $this->error('该手机号已绑定QQ'.$bind_type);
+                if(empty($access_token)) $this->error('参数错误');
+                $res = curl_get('https://graph.qq.com/oauth2.0/me?access_token='.$access_token.'&unionid=1'.'&fmt=json');
+                if(!$res || !isset($res['unionid'])) $this->error('获取unionid有误');
+                $check_qq = User::where('qq_unionid', $res['unionid'])->value('id');
+                if($check_qq) $this->error('用户已存在');
+                $bind_data['qq_unionid'] = $res['unionid'];
+                if($is_new) $bind_data['name']   = $nickname;
+                if($is_new) $bind_data['headimg'] = $headimgurl;
+                break;
+            case 5:// pc qq
+                if(empty($access_token)) $this->error('参数错误');
+                $res = curl_get('https://graph.qq.com/oauth2.0/me?access_token='.$access_token.'&unionid=1'.'&fmt=json');
+                if(!$res || !isset($res['unionid'])) $this->error('获取unionid有误');
+                $check_qq = User::where('qq_unionid', $res['unionid'])->value('id');
+                if($check_qq) $this->error('用户已存在');
+                $bind_data['qq_unionid'] = $res['unionid'];
+                if($is_new) $bind_data['name']   = $nickname;
+                if($is_new) $bind_data['headimg'] = $headimgurl;
+                break;
+        }
+        // 新用户创建钱包
+        if($is_new){
+            if(empty($bind_data['headimg'])) $bind_data['headimg'] = 'https://xieshouxiongmao.oss-cn-beijing.aliyuncs.com/add09dc3edac6bfd/c15ab257e41b46ba.png';
+            if(empty($bind_data['name'])) $bind_data['name'] = $phone;
+            $member = User::create($bind_data);
+            User::update(['invite_code'=>create_invite_code($member->id)],['id'=>$member->id]);
+            Data::save("UserWallet",['user_id'=>$member->id],'user_id',['user_id'=>$member->id]);//创建钱包
+            if($pid) InviteInfo::create(['user_id'=>$member->id,'pid'=>$pid,'create_at'=>date('Y-m-d H:i:s')]);
+        }else{
+            User::where('id',$member->id)->update($bind_data);
+        }
+        $token = $this->createJwt($member->id);
+        $this->success('绑定成功', ['token' => $token]);
+    }
+
+    /**
+     * @title 手机验正码注册
+     * @desc 手机验正码注册
+     * @author qc
+     * @url /api/Login/phoneCodeRegister
+     * @method POST
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:string require:1 default:-- desc:手机验证码
+     * @param name:verify type:string require:1 default:-- desc:图形验证码
+     * @param name:pid type:string require:0 default:-- desc:推荐人id
+     * @param name:uniqid type:string require:1 default:-- desc:生成验证码图形时返回的uniqid
+     * @param name:password type:string require:1 default:-- desc:密码
+     * @param name:con_password type:string require:1 default:-- desc:确认密码
+     * @return name:token type:string default:-- desc:用户登录成功后的token值
+     */
+    public function phoneCodeRegister()
+    {
+        $verify = input('post.verify');
+        $uniqid = input('post.uniqid');
+        $phone = input('post.phone');
+        $code = input('post.code');
+        $password = input('post.password');
+        $con_password = input('post.con_password');
+        $pid = input('pid', 0);
+        if($password !== $con_password) $this->error('两次输入密码不一致');
+        if (!CaptchaService::instance()->check($verify, $uniqid)) $this->error('图形验证码验证失败,请重新输入!');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $this->updatePhoneCode($check_code);
+        $member = User::field('id,phone')->where('phone', $phone)->find();
+        if($member) $this->error('该手机号已注册');
+        $member_data = ['phone' => $phone,'encryption_password'=>encrypt_password($password)];
+        Db::name('store_member')->insert($member_data);
+        $uid = Db::getLastInsID();
+        User::update(['invite_code'=>create_invite_code($uid)],['id'=>$uid]);
+        UserWallet::create(['user_id'=>$uid]);//创建钱包
+        if($pid) InviteInfo::create(['user_id'=>$uid,'pid'=>$pid,'create_at'=>date('Y-m-d H:i:s')]);
+        $token = $this->createJwt($uid);
+        $this->success('登录成功', ['token' => $token]);
+    }
+
+
+    /**
+     * @title 获取验证码
+     * @desc 获取验证码
+     * @author qc
+     * @url /api/Login/getCaptcha
+     * @method GET
+     * @return name:image type:string default:-- desc:图片
+     * @return name:uniqid type:string default:-- desc:uniqid
+     */
+    public function getCaptcha()
+    {
+        $image = CaptchaService::instance();
+        $captcha = ['image' => $image->getData(), 'uniqid' => $image->getUniqid()];
+        $this->success('生成验证码成功', $captcha);
+    }
+
+    /**
+     * @title 重置密码
+     * @desc 重置密码
+     * @author qc
+     * @url /api/Login/resetPassword
+     * @method POST
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:string require:1 default:-- desc:手机验证码
+     * @param name:verify type:string require:1 default:-- desc:图形验证码
+     * @param name:uniqid type:string require:1 default:-- desc:生成验证码图形时返回的uniqid
+     * @param name:password type:string require:1 default:-- desc:密码
+     * @param name:con_password type:string require:1 default:-- desc:确认密码
+     */
+    public function resetPassword()
+    {
+        $verify = input('post.verify');
+        $uniqid = input('post.uniqid');
+        $phone = input('post.phone');
+        $code = input('post.code');
+        $password = input('post.password');
+        $con_password = input('post.con_password');
+        $validate = new UserVali();
+        if (!$validate->scene('reset_password')->check(['phone'=>$phone,'password'=>$password])) {
+            $this->error($validate->getError());
+        }
+        if (!CaptchaService::instance()->check($verify, $uniqid)) $this->error('图形验证码验证失败,请重新输入!');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $user_id = User::where('phone',$phone)->value('id');
+        if(!$user_id) $this->error('账号不存在');
+        if($password !== $con_password) $this->error('两次输入密码不一致');
+        User::where(['phone'=>$phone])->update(['encryption_password'=>encrypt_password($password)]);
+        $this->success('修改密码成功');
+    }
+
+
+    public function weChatLogin()
+    {
+        $code = input('post.code');
+        $headimg = input('post.headimg');
+        $name = input('post.name');
+        $pid = input('post.pid', 0);
+        if (empty($code) || empty($headimg) || empty($name)) $this->error('参数错误');
+        $app = Factory::miniProgram(config('app.mini_program'));
+        $data = $app->auth->session($code);
+        if (empty($data['openid'])) {
+            $this->error($data['errmsg']);
+        }
+        $member = Db::name('store_member')->field('id,phone')->where('openid', $data['openid'])->find();
+        if (empty($member)) {
+            $member_data = array(
+                'openid' => $data['openid'],
+                'headimg' => $headimg,
+                'name' => $name,
+                'pid' => $pid,
+                'create_at' => date("Y-m-d H:i:s")
+            );
+            Db::name('store_member')->insert($member_data);
+            $uid = Db::getLastInsID();
+            User::update(['invite_code'=>create_invite_code($uid)],['id'=>$uid]);
+            UserWallet::create(['user_id'=>$uid]);//创建钱包
+            if($pid) InviteInfo::create(['user_id'=>$uid,'pid'=>$pid,'create_at'=>date('Y-m-d H:i:s')]);
+        } else {
+            $uid = $member['id'];
+        }
+        if (empty($uid)) $this->error('数据有误');
+        $token = $this->createJwt($uid);
+        $this->success('登录成功', ['token' => $token,'phone'=>empty($member)  ?'' :$member['phone']]);
+    }
+
+    public function weChatAppLogin()
+    {
+        $code = input('post.code');
+        if(empty($code)) $this->error('参数错误');
+        $res = http_curl('https://api.weixin.qq.com/sns/oauth2/access_token?appid='.config('app_wx')['app_id'].'&secret='.config('app_wx')['secret'].'&code='.$code.'&grant_type=authorization_code');
+        if(!$res) $this->error('获取access_token有误');
+        $user_info = http_curl('https://api.weixin.qq.com/sns/userinfo?access_token='.$res['access_token'].'&openid='.$res['openid']);
+        if(!$user_info) $this->error('获取用户微信信息有误');
+        $data['app_openid'] = $user_info['openid'];
+        $data['name'] = $user_info['nickname'];
+        $data['headimg'] = $user_info['headimgurl'];
+        $data['token'] = '';
+        $member = User::where('app_openid',$data['app_openid'])->find();
+        if(!$member) $this->success('授权成功',$data);
+        $token = $this->createJwt($member->id);
+        $data['token'] = $token;
+        $this->success('登录成功',$data);
+    }
+
+    public function weChatPcLogin()
+    {
+        $code = input('post.code');
+        $res = http_get('https://api.weixin.qq.com/sns/oauth2/access_token?appid='.config('pc_wx')['app_id'].'&secret='.config('pc_wx')['secret'].'&code='.$code.'&grant_type=authorization_code');
+        if(!$res) $this->error('获取access_token有误');
+        $user_info = http_get('https://api.weixin.qq.com/sns/userinfo?access_token='.$res['access_token'].'&openid='.$res['openid']);
+        $data['pc_openid'] = $user_info['openid'];
+        $data['name'] = $user_info['nickname'];
+        $data['headimg'] = $user_info['headimgurl'];
+        $member = User::where('pc_openid',$data['pc_openid'])->find();
+        if(!$member) $this->success('授权成功',$data);
+        $token = $this->createJwt($member->id);
+        $data['token'] = $token;
+        $this->success('登录成功',$data);
+    }
+
+    public function phoneCodeLogin()
+    {
+        $phone = input('post.phone');
+        $code = input('post.code');
+        $member = Db::name('store_member')->field('id,phone')->where('phone', $phone)->find();
+        if(empty($phone)) $this->error('用户不存在,请先注册');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $this->updatePhoneCode($check_code);
+        $uid = $member['id'];
+        $token = $this->createJwt($uid);
+        $this->success('登录成功', ['token' => $token,'phone'=>empty($member)  ?'' :$member['phone']]);
+    }
+
+    public function passwordLogin()
+    {
+        $phone = input('post.phone');
+        $password = input('post.password');
+        if (empty($password) || empty($phone)) $this->error('参数错误');
+        $member = Db::name('store_member')->where('phone', $phone)->find();
+        if(!$member) $this->error('用户不存在');
+        if(!check_password($password,$member['encryption_password'])) $this->error('密码错误');
+        $token = self::createJwt($member['id']);
+        $this->success('登录成功', ['token' => $token]);
+    }
+    /**
+     * @title 获取版本号
+     * @desc 获取版本号
+     * @author QGF
+     * @url /api/Login/get_store_versions
+     * @method GET
+     * @tag 获取版本号
+     * @param name:type type:int require:1 default:1 desc:类型(1:安卓,2:IOS。默认安卓)
+     * @return name:title type:string default:-- desc:版本号
+     * @return name:content type:string default:-- desc:修改内容
+     * @return name:url type:string default:-- desc:下載地址(安卓有值)
+     */
+    public function get_store_versions(){
+        $type = input('type',1);
+        $store_versions = Db::name('store_versions')->field('title,content,url')->where('type',$type)->find();
+        $this->success('获取成功',$store_versions);
+    }
+
+}

+ 518 - 0
application/api/controller/MallActivity.php

@@ -0,0 +1,518 @@
+<?php
+
+namespace app\api\controller;
+use app\common\model\DiscountActivity;
+use app\common\model\DiscountGoods;
+use app\common\model\GiftCate;
+use app\common\model\GoodsOrder;
+use app\common\model\GoodsOrderItem;
+use app\common\model\GoodsSellInfo;
+use app\common\model\GroupActivity;
+use app\common\model\GroupLeader;
+use app\common\model\SeckillActivity;
+use app\common\model\SeckillGoods;
+use app\common\model\SeckillGoodsItem;
+use app\common\model\GroupGoods;
+use app\common\model\GroupGoodsItem;
+use app\common\model\GiftGoods;
+
+/**
+ * @title 商城活动&&商品(秒杀&&拼团&&心选商品)
+ * @controller MallActivity
+ * @package app\api\controller
+ */
+class MallActivity extends Base
+{
+    public function initialize(){
+        parent::initialize();
+        parent::setUid();
+    }
+
+    /**
+     * @title 获取秒杀活动列表
+     * @desc 获取秒杀活动列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getSeckillActivityList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:3 desc:查询条数
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:图片
+     * @return name:create_at type:string default:-- desc:开始时间
+     * @return name:end_time type:string default:-- desc:结束时间
+     * @return name:start_point type:string default:-- desc:开始时间点
+     * @return name:end_point type:string default:-- desc:结束时间点
+     */
+    public function getSeckillActivityList()
+    {
+        $num = input('num,3');
+        $list = SeckillActivity::where([['status','=',1],['end_time','> time',date('Y-m-d H:i:s')],['is_deleted','=',0]])
+            ->order('sort desc,id asc')->limit(0,$num)->select()->toArray();
+        foreach ($list as &$v){
+            $v['start_point'] = date('H:i',strtotime($v['start_time']));
+            $v['end_point'] = date('H:i',strtotime($v['end_time']));
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取秒杀活动商品列表
+     * @desc 获取秒杀活动商品列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getSeckillGoodsList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:page type:int require:1 default:-- desc:第几页
+     * @param  name:page_num type:int require:1 default:20 desc:每页数
+     * @return name:id type:int default:-- desc:活动商品记录id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:seckill_low type:string default:-- desc:抢购最低价
+     * @return name:seckill_num type:int default:-- desc:秒杀订单数量
+     */
+    public function getSeckillGoodsList()
+    {
+        $act_id = input('act_id');
+        $goods_list = SeckillGoods::field('s.*,g.name,g.cover,g.low_price')->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.act_id'=>$act_id])
+            ->order('s.sort desc , s.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($goods_list,function (&$v,$k)use($act_id){
+            $v['seckill_low'] = SeckillGoodsItem::where(['act_id'=>$v['act_id'],'goods_id'=>$v['goods_id']])->min('seckill_price');
+            $v['seckill_num'] = GoodsSellInfo::where(['goods_id'=>$v['id'],'act_type'=>2,'act_id'=>$act_id])->count();
+        });
+        $this->success('ok',['list'=>$goods_list]);
+    }
+
+    /**
+     * @title 获取秒杀活动商品详情
+     * @desc 获取秒杀活动商品详情
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getSeckillGoodsDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:goods_id type:int require:1 default:-- desc:活动id
+     * @return name:id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面图
+     * @return name:desc type:string default:-- desc:商品简述
+     * @return name:goods_price type:float default:-- desc:价格
+     * @return name:detail type:int default:-- desc:商品详情
+     * @return name:stock type:float default:-- desc:剩余库存
+     * @return name:base_stock type:float default:-- desc:初始库存
+     * @return name:freight_type type:int default:-- desc:运费类型0固定金额,1运费模板
+     * @return name:freight_id type:int default:-- desc:模板id(freight_type=1)
+     * @return name:postage type:float default:-- desc:运费(freight_type=0)
+     * @return name:goods_param type:array default:-- desc:商品相关参数
+     * @return name:goods_param.title type:string default:-- desc:参数名
+     * @return name:goods_param.value type:string default:-- desc:参数值
+     * @return name:seckill_item type:array default:-- desc:秒杀规格设置
+     * @return name:seckill_item.goods_spec type:string default:-- desc:规格
+     * @return name:seckill_item.original_price type:float default:-- desc:原价
+     * @return name:seckill_item.sell_price type:float default:-- desc:售价
+     * @return name:seckill_item.seckill_price type:float default:-- desc:秒杀价
+     * @return name:seckill_item.stock type:float default:-- desc:改规格剩余库存
+     */
+    public function getSeckillGoodsDetail()
+    {
+        $act_id = input('act_id');
+        $goods_id = input('goods_id');
+        $goods_info = SeckillGoods::where(['s.goods_id'=>$goods_id,'s.act_id'=>$act_id])
+            ->field('g.*,s.id s_id,s.act_id,s.act_id,p.goods_param')
+            ->alias('s')
+            ->leftJoin('StoreGoods g','s.goods_id = g.id')
+            ->leftJoin('GoodsParam p','s.goods_id = p.goods_id')
+            ->find()->toArray();
+        $goods_info['seckill_item'] = SeckillGoodsItem::field('s.id,s.original_price,s.sell_price,s.seckill_price,i.stock,i.goods_spec')->alias('s')
+            ->leftJoin('StoreGoodsItem i','i.id = s.spec_id')
+            ->where(['s.act_id'=>$act_id,'s.goods_id'=>$goods_id])
+            ->select()->toArray();// 秒杀设置
+        $this->success('ok',['detail'=>$goods_info]);
+    }
+
+    /**
+     * @title 获取拼团活动列表
+     * @desc 获取拼团活动列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGroupActivityList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:3 desc:查询条数
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:图片
+     * @return name:full_num type:int default:-- desc:成团人数
+     * @return name:create_at type:string default:-- desc:开始时间
+     * @return name:end_time type:string default:-- desc:结束时间
+     * @return name:start_point type:string default:-- desc:开始时间点
+     * @return name:end_point type:string default:-- desc:结束时间点
+     */
+    public function getGroupActivityList()
+    {
+        $num = input('num,3');
+        $list = GroupActivity::where([['status','=',1],['end_time','> time',date('Y-m-d H:i:s')],['is_deleted','=',0]])
+            ->order('sort desc,id asc')->limit(0,$num)->select()->toArray();
+        foreach ($list as &$v){
+            $v['start_point'] = date('H:i',strtotime($v['start_time']));
+            $v['end_point'] = date('H:i',strtotime($v['end_time']));
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取拼团活动商品列表
+     * @desc 获取拼团活动商品列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGroupGoodsList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:page type:int require:1 default:-- desc:第几页
+     * @param  name:page_num type:int require:1 default:20 desc:每页数
+     * @return name:id type:int default:-- desc:活动商品记录id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:group_low type:string default:-- desc:拼团最低价
+     * @return name:success_num type:int default:-- desc:拼团成功团数量
+     * @return name:present_num type:int default:-- desc:进行中的团数量
+     */
+    public function getGroupGoodsList()
+    {
+        $act_id = input('act_id');
+        $goods_list = GroupGoods::field('s.*,g.name,g.cover,g.low_price')->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.act_id'=>$act_id])
+            ->order('s.sort desc , s.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($goods_list,function (&$v,$k)use($act_id){
+            $v['group_low'] = GroupGoodsItem::where(['act_id'=>$v['act_id'],'goods_id'=>$v['goods_id']])->min('group_price');
+            $v['success_num'] = GroupLeader::where(['act_id'=>$act_id,'goods_id'=>$v['goods_id'],'status'=>1])->count();
+            $v['present_num'] = GroupLeader::where(['act_id'=>$act_id,'goods_id'=>$v['goods_id'],'status'=>0])->count();
+        });
+        $this->success('ok',['list'=>$goods_list]);
+    }
+
+    /**
+     * @title 获取拼团活动商品详情
+     * @desc 获取拼团活动商品详情
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGroupGoodsDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:goods_id type:int require:1 default:-- desc:活动id
+     * @return name:id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面图
+     * @return name:desc type:string default:-- desc:商品简述
+     * @return name:goods_price type:float default:-- desc:价格
+     * @return name:detail type:int default:-- desc:商品详情
+     * @return name:stock type:float default:-- desc:剩余库存
+     * @return name:base_stock type:float default:-- desc:初始库存
+     * @return name:freight_type type:int default:-- desc:运费类型0固定金额,1运费模板
+     * @return name:freight_id type:int default:-- desc:模板id(freight_type=1)
+     * @return name:postage type:float default:-- desc:运费(freight_type=0)
+     * @return name:goods_param type:array default:-- desc:商品相关参数
+     * @return name:goods_param.title type:string default:-- desc:参数名
+     * @return name:goods_param.value type:string default:-- desc:参数值
+     * @return name:group_item type:array default:-- desc:秒杀规格设置
+     * @return name:group_item.goods_spec type:string default:-- desc:规格
+     * @return name:group_item.original_price type:float default:-- desc:原价
+     * @return name:group_item.sell_price type:float default:-- desc:售价
+     * @return name:group_item.group_price type:float default:-- desc:秒杀价
+     * @return name:group_item.stock type:float default:-- desc:改规格剩余库存
+     */
+    public function getGroupGoodsDetail()
+    {
+        $act_id = input('act_id');
+        $goods_id = input('goods_id');
+        $goods_info = GroupGoods::where(['s.goods_id'=>$goods_id,'s.act_id'=>$act_id])
+            ->field('g.*,s.id s_id,s.act_id,s.act_id,p.goods_param')
+            ->alias('s')
+            ->leftJoin('StoreGoods g','s.goods_id = g.id')
+            ->leftJoin('GoodsParam p','s.goods_id = p.goods_id')
+            ->find()->toArray();
+        $goods_info['group_item'] = GroupGoodsItem::field('s.id,s.original_price,s.sell_price,s.group_price,i.stock, i.goods_spec')->alias('s')
+            ->leftJoin('StoreGoodsItem i','i.id = s.spec_id')
+            ->where(['s.act_id'=>$act_id,'s.goods_id'=>$goods_id])
+            ->select()->toArray();// 秒杀设置
+        $this->success('ok',['detail'=>$goods_info]);
+    }
+
+    /**
+     * @title 获取正在拼团列表
+     * @desc 获取正在拼团列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGroupLeaderList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:goods_id type:int require:1 default:-- desc:活动id
+     * @return name:name type:string default:-- desc:名称
+     * @return name:headimg type:string default:-- desc:头像
+     * @return name:num type:int default:-- desc:数量
+     */
+    public function getGroupLeaderList()
+    {
+        $act_id = input('get.act_id');
+        $goods_id = input('get.goods_id');
+        $list = GroupLeader::field('l.id,l.goods_id,l.spec_id,l.create_at,u.name,u.headimg')
+            ->alias('l')
+            ->where(['l.act_id'=>$act_id,'l.goods_id'=>$goods_id,'l.status'=>0])
+            ->leftJoin('StoreMember u','u.id = l.user_id')
+            ->order('l.id asc')
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list,'num'=>count($list)]);
+    }
+
+    /**
+     * @title 获取折扣活动列表
+     * @desc 获取折扣活动列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getDiscountActivityList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:3 desc:查询条数
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:图片
+     * @return name:create_at type:string default:-- desc:开始时间
+     * @return name:end_time type:string default:-- desc:结束时间
+     * @return name:start_point type:string default:-- desc:开始时间点
+     * @return name:end_point type:string default:-- desc:结束时间点
+     */
+    public function getDiscountActivityList()
+    {
+        $num = input('num,3');
+        $list = DiscountActivity::where([['status','=',1],['end_time','> time',date('Y-m-d H:i:s')],['is_deleted','=',0]])
+            ->order('sort desc,id asc')->limit(0,$num)->select()->toArray();
+        foreach ($list as &$v){
+            $v['start_point'] = date('H:i',strtotime($v['start_time']));
+            $v['end_point'] = date('H:i',strtotime($v['end_time']));
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取折扣活动商品列表
+     * @desc 获取折扣活动商品列表
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getDiscountGoodsList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:act_id type:int require:1 default:-- desc:活动id
+     * @param  name:page type:int require:1 default:-- desc:第几页
+     * @param  name:page_num type:int require:1 default:20 desc:每页数
+     * @return name:id type:int default:-- desc:活动商品记录id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:float default:-- desc:最低价(正常售价)
+     * @return name:discount_price type:float default:-- desc:最低价(折扣价)
+     * @return name:discount type:float default:-- desc:折扣
+     * @return name:line_price type:float default:-- desc:下划线价格
+     * @return name:discount_act type:int default:-- desc:折扣活动详情
+     * @return name:discount_act.id type:int default:-- desc:活动id
+     */
+    public function getDiscountGoodsList()
+    {
+        $act_id = input('act_id');
+        $discount_act = DiscountActivity::where('id',$act_id)->find()->toArray();
+        $price_discount = bcdiv($discount_act['discount'],100,2);
+        $goods_list = DiscountGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.act_id'=>$act_id])
+            ->order('s.sort desc , s.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($goods_list,function (&$v,$k)use($act_id,$price_discount){
+            $v['discount_price'] = bcmul($v['low_price'],$price_discount,2);
+            $v['line_price'] = GoodsOrderItem::where(['goods_id'=>$v['id']])->max('sell_price');
+            $v['discount'] = $price_discount*10;
+
+        });
+        $this->success('ok',['list'=>$goods_list,'discount'=>$price_discount,'discount_act'=>$discount_act]);
+    }
+
+    /**
+     * @title 获取心选礼物分类
+     * @desc 获取心选礼物分类
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGiftCate
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:string default:-- desc:标题
+     * @return name:logo type:string default:-- desc:封面
+     */
+    public function getGiftCate()
+    {
+        $gift_cate = GiftCate::field('id,title,logo')->where(['is_deleted'=>0])->select()->toArray();
+        $this->success('ok',['list'=>$gift_cate]);
+    }
+
+    /**
+     * @title 获取推荐心选商品
+     * @desc 获取推荐心选商品
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGiftHotGoods
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int require:1 default:-- desc:第几页
+     * @param  name:page_num type:int require:1 default:20 desc:每页数
+     * @return name:is_custom type:int default:-- desc:是否允许定制(0否1是)
+     * @return name:custom_cover type:string default:-- desc:定制风格(多图|隔开)
+     * @return name:custom_color type:string default:-- desc:定制色系图(多图|隔开)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:line_price type:string default:-- desc:下划线价格
+     */
+    public function  getGiftHotGoods()
+    {
+        $goods_list = GiftGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.status'=>1,'s.is_hot'=>1,'s.is_deleted'=>0,'g.is_deleted'=>0,'g.status'=>1])
+            ->order('s.sort desc , s.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($goods_list,function (&$v,$k){
+            $v['line_price'] = GoodsOrderItem::where('goods_id',$v['goods_id'])->max('original_price');
+        });
+        $this->success('ok',['list'=>$goods_list]);
+    }
+
+    /**
+     * @title 根据分类获取心选商品
+     * @desc 根据分类获取心选商品
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGiftGoodsByCate
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int require:1 default:-- desc:第几页
+     * @param  name:page_num type:int require:1 default:20 desc:每页数
+     * @param  name:cate_id type:int require:1 desc:心选礼物分类id
+     * @return name:is_custom type:int default:-- desc:是否允许定制(0否1是)
+     * @return name:custom_cover type:string default:-- desc:定制风格(多图|隔开)
+     * @return name:custom_color type:string default:-- desc:定制色系图(多图|隔开)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:line_price type:string default:-- desc:下划线价格
+     */
+    public function getGiftGoodsByCate()
+    {
+        $goods_list = GiftGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where(['s.status'=>1,'s.is_deleted'=>0,'g.is_deleted'=>0,'g.status'=>1,'s.cate_id'=>input('get.cate_id')])
+            ->order('s.sort desc , s.id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($goods_list,function (&$v,$k){
+            $v['line_price'] = GoodsOrderItem::where('goods_id',$v['goods_id'])->max('original_price');
+        });
+        $this->success('ok',['list'=>$goods_list]);
+    }
+
+    /**
+     * @title 获取定制商品
+     * @desc 获取定制商品
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getCustomGoodsList
+     * @header name:Authorization require:1 desc:Token
+     * @return name:is_custom type:int default:-- desc:是否允许定制(0否1是)
+     * @return name:custom_cover type:string default:-- desc:定制风格(多图|隔开)
+     * @return name:custom_color type:string default:-- desc:定制色系图(多图|隔开)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:item_list type:array default:-- desc:商品多规格列表
+     * @return name:item_list.spec_info type:array default:-- desc:规格型号设置;
+     * @return name:item_list.goods_no type:string default:-- desc:规格货号
+     * @return name:item_list.goods_title type:string default:-- desc:规格标题
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.stock type:int default:-- desc:剩余库存
+     * @return name:item_list.original_price type:float default:-- desc:原价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     */
+    public function getCustomGoodsList()
+    {
+        $where = [];
+        $where[] = ['s.status','=',1];
+        $where[] = ['s.is_deleted','=',0];
+        $where[] = ['g.is_deleted','=',0];
+        $where[] = ['g.status','=',1];
+        $where[] = ['s.is_custom','=',1];
+        $list = GiftGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->with('itemList')
+            ->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where($where)
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 心选商品设置
+     * @desc 心选商品设置
+     * @author qc
+     * @method GET
+     * @url /api/Mall_activity/getGiftGoodsDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int require:1 desc:心选商品记录id(两个不能同时为空)
+     * @param  name:goods_id type:int require:1 desc:商品id(两个不能同时为空)
+     * @return name:is_custom type:int default:-- desc:是否允许定制(0否1是)
+     * @return name:custom_cover type:string default:-- desc:定制风格(多图|隔开)
+     * @return name:custom_color type:string default:-- desc:定制色系图(多图|隔开)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:low_price type:string default:-- desc:最低价(正常售价)
+     * @return name:item_list type:array default:-- desc:商品多规格列表
+     * @return name:item_list.spec_info type:array default:-- desc:规格型号设置;
+     * @return name:item_list.goods_no type:string default:-- desc:规格货号
+     * @return name:item_list.goods_title type:string default:-- desc:规格标题
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.stock type:int default:-- desc:剩余库存
+     * @return name:item_list.original_price type:float default:-- desc:原价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     */
+    public function getGiftGoodsDetail()
+    {
+        $where = [];
+        $where[] = ['s.status','=',1];
+        $where[] = ['s.is_deleted','=',0];
+        $where[] = ['g.is_deleted','=',0];
+        $where[] = ['g.status','=',1];
+        if(input('get.id')) $where[] = ['s.id','=',input('get.id')];
+        if(input('get.goods_id')) $where[] = ['s.goods_id','=',input('get.goods_id')];
+        $detail = GiftGoods::field('s.*,g.name,g.cover,g.low_price')
+            ->with('itemList')
+            ->alias('s')->leftJoin('StoreGoods g','g.id = s.goods_id')
+            ->where($where)
+            ->find();
+        if(!$detail)  $this->error('商品已下架');
+        $this->success('ok',['detail'=>$detail->toArray()]);
+    }
+
+
+
+
+
+
+
+
+
+
+}

+ 387 - 0
application/api/controller/MallIndex.php

@@ -0,0 +1,387 @@
+<?php
+
+
+namespace app\api\controller;
+use app\common\model\DiscountGoods;
+use app\common\model\GiftGoods;
+use app\common\model\GoodsColumn;
+use app\common\model\GoodsOrder;
+use app\common\model\GoodsOrderItem;
+use app\common\model\InformationArticle;
+use app\common\model\InformationGoods;
+use app\common\model\MallMenu;
+use app\common\model\MenuGoods;
+use app\common\model\RegionMenu;
+use app\common\model\RegionGoods;
+use app\common\model\SeckillActivity;
+use app\common\model\SeckillGoods;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\SystemConfig;
+
+/**
+ * @title 商城首页
+ * @controller MallIndex
+ * @package app\api\controller
+ */
+class MallIndex extends Base
+{
+
+    public function initialize()
+    {
+        parent::initialize();
+        parent::setUid();
+    }
+
+    /**
+     * @title 获取首页公告
+     * @desc  获取首页公告
+     * @author  qc
+     * @url /api/Mall_index/getIndexNotice
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:detail type:srting default:-- desc:公告内容
+     */
+    public function getIndexNotice()
+    {
+        $detail = SystemConfig::where(['name'=>'index_notice'])->value('value');
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+
+    /**
+     * @title 获取首页菜单(一级)
+     * @desc  获取首页菜单(一级)
+     * @author  qc
+     * @url /api/Mall_index/getIndexMenu
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:num type:int  default:10 desc:查询数量
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:logo type:srting default:-- desc:图片路径
+     */
+    public function getIndexMenu()
+    {
+        $num = input('get.num', 10);
+        $list = MallMenu::field('id,title,logo')->where('is_deleted', 0)
+            ->where('pid', 0)
+            ->order('sort desc ,id desc')
+            ->limit(0, $num)->select()->toArray();
+        $this->success('ok', $list);
+    }
+
+    /**
+     * @title 获取首页菜单(二级)
+     * @desc  获取首页菜单(二级)
+     * @author  qc
+     * @url /api/Mall_index/getSecondIndexMenu
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:id type:int default:-- desc:菜单id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:logo type:srting default:-- desc:图片路径
+     */
+    public function getSecondIndexMenu()
+    {
+        $pid = input('get.id');
+        $list = MallMenu::field('id,title,logo')->where('is_deleted', 0)
+            ->where('pid', $pid)
+            ->order('sort desc ,id asc')
+            ->select()->toArray();
+        $this->success('ok', $list);
+    }
+
+    /**
+     *
+     * @title 获取首页菜单关联商品
+     * @desc  获取首页菜单关联商品
+     * @author  qc
+     * @url /api/Mall_index/getMallMenuGoods
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:page type:int default:1 desc:页数
+     * @param name:page_num type:int default:20 desc:每页数
+     * @param name:second_id type:int default:-- desc:菜单id(二级菜单id)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:srting default:-- desc:商品名称
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:low_price type:float default:-- desc:最低价
+     * @return name:max_price type:float default:-- desc:下划线价格
+     */
+    public function getMallMenuGoods()
+    {
+        $second_id = input('get.second_id');
+        $where = [];
+        $where[] = ['m.second_menu', '=', $second_id];
+        $where[] = ['g.is_deleted', '=', 0];
+        $where[] = ['g.status', '=', 1];
+        $list = MenuGoods::field('m.id as mid,m.goods_id,g.id,g.name,g.cover,g.desc,g.low_price')->alias('m')
+            ->where($where)
+            ->leftJoin('StoreGoods g', 'g.id = m.goods_id')
+            ->order('m.sort desc ,m.id desc')
+            ->limit($this->off_set, $this->page_num)
+            ->select()->toArray();
+        array_walk($list, function (&$v, $k) {
+            $v['max_price'] = GoodsOrderItem::where('goods_id', $v['id'])->max('original_price');
+        });
+        $this->success('ok', ['list' => $list]);
+
+    }
+
+    /**
+     *
+     * @title 获取首页菜单搭配商品
+     * @desc  获取首页菜单搭配商品
+     * @author  qc
+     * @url /api/Mall_index/getRecommendGoods
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:page type:int default:1 desc:页数
+     * @param name:page_num type:int default:20 desc:每页数
+     * @param name:first_id type:int default:-- desc:菜单id(1级菜单id)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:srting default:-- desc:商品名称
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:content type:srting default:-- desc:图片(多张用|隔开)
+     * @return name:low_price type:float default:-- desc:最低价
+     * @return name:max_price type:float default:-- desc:下划线价格
+     */
+    public function getRecommendGoods()
+    {
+        $first_id = input('get.first_id');
+        $where = [];
+        $where[] = ['m.first_menu', '<>', $first_id];
+        $where[] = ['g.is_deleted', '=', 0];
+        $where[] = ['g.status', '=', 1];
+        $list = MenuGoods::field('m.id as mid,m.goods_id,g.id,g.name,g.cover,g.desc,g.low_price,content')->alias('m')
+            ->where($where)
+            ->leftJoin('StoreGoods g', 'g.id = m.goods_id')
+            ->order('m.sort desc ,m.id desc')
+            ->limit($this->off_set, $this->page_num)
+            ->select()->toArray();
+        array_walk($list, function (&$v, $k) {
+            $v['max_price'] = GoodsOrderItem::where('goods_id', $v['id'])->max('original_price');
+        });
+        $this->success('ok', ['list' => $list]);
+
+    }
+
+
+    /**
+     * @title 获取首页推荐商品区(一级)
+     * @desc  获取首页推荐商品区(一级)
+     * @author  qc
+     * @url /api/Mall_index/getIndexRegion
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:num type:int  default:10 desc:查询数量
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:desc type:srting default:-- desc:简介
+     * @return name:logo type:srting default:-- desc:图片路径
+     */
+    public function getIndexRegion()
+    {
+        $num = input('get.num', 10);
+        $list = RegionMenu::field('id,title,desc,logo')->where('is_deleted', 0)
+            ->where('pid', 0)
+            ->order('sort desc ,id desc')
+            ->limit(0, $num)->select()->toArray();
+        $this->success('ok', $list);
+    }
+
+    /**
+     * @title 获取首页专区详情(最多三级)
+     * @desc  获取首页专区详情
+     * @author  qc
+     * @url /api/Mall_index/getRegionMenu
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:id type:int default:-- desc:专区id
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:logo type:srting default:-- desc:图片路径
+     */
+    public function getRegionMenu()
+    {
+        $id = input('get.id');
+        $region = RegionMenu::field('id,title,logo,pid')->where('id', $id)->find()->toArray();
+        $region['children'] = RegionMenu::field('id,title,logo,pid')->where('pid', $region['id'])->where('is_deleted', 0)->select()->toArray();
+        if (!empty($region['children'])) {
+            foreach ($region['children'] as $k => $v) {
+                $region['children'][$k]['children'] = RegionMenu::field('id,title,logo,pid')->where('pid', $v['id'])->where('is_deleted', 0)->select()->toArray();
+            }
+        }
+        $this->success('ok', ['detail' => $region]);
+    }
+
+
+    /**
+     * @title 获取首页专区关联商品
+     * @desc  获取首页专区关联商品
+     * @author  qc
+     * @url /api/Mall_index/getRegionMenuGoods
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:page type:int default:1 desc:页数
+     * @param name:page_num type:int default:20 desc:每页数
+     * @param name:first_region type:int default:-- desc:第一等级id
+     * @param name:second_region type:int default:-- desc:第二等级id
+     * @param name:third_region type:int default:-- desc:第三等级id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:srting default:-- desc:商品名称
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:low_price type:float default:-- desc:最低价
+     * @return name:max_price type:float default:-- desc:下划线价格
+     */
+    public function getRegionMenuGoods()
+    {
+        $first_region = input('get.first_region');
+        $second_region = input('get.second_region');
+        $third_region = input('get.third_region');
+        $where = [];
+        if ($first_region) $where[] = ['m.first_region', '=', $first_region];
+        if ($second_region) $where[] = ['m.second_region', '=', $second_region];
+        if ($third_region) $where[] = ['m.third_region', '=', $third_region];
+        $where[] = ['g.is_deleted', '=', 0];
+        $where[] = ['g.status', '=', 1];
+        $list = RegionGoods::field('m.id as mid,m.goods_id,g.id,g.name,g.cover,g.desc,g.low_price')->alias('m')
+            ->where($where)
+            ->leftJoin('StoreGoods g', 'g.id = m.goods_id')
+            ->order('m.sort desc ,m.id desc')
+            ->limit($this->off_set, $this->page_num)
+            ->select()->toArray();
+        array_walk($list, function (&$v, $k) {
+            $v['max_price'] = GoodsOrderItem::where('goods_id', $v['id'])->max('original_price');
+        });
+        $this->success('ok', ['list' => $list]);
+    }
+
+    /**
+     * @title 获取首页商品推荐专栏
+     * @desc  获取首页商品推荐专栏
+     * @author  qc
+     * @url /api/Mall_index/getGoodsColumn
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:srting default:-- desc:标题
+     * @return name:desc type:srting default:-- desc:描述
+     */
+    public function getGoodsColumn()
+    {
+        $list = GoodsColumn::field('id,desc,title')->where(['status' => 1, 'is_deleted' => 0])->order('sort desc ,id asc')->select()->toArray();
+        $this->success('ok', ['list' => $list]);
+    }
+
+    /**
+     * @title 获取专区模块推荐商品
+     * @desc  第一个亚健康,第二个礼品心选,第三个秒杀(促销)第四个预售
+     * @author  qc
+     * @url /api/Mall_index/getRegionRecommend
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:2 desc:查询数量
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:name type:string default:-- desc:商品名
+     * @return name:low_price type:string default:-- desc:价格
+     * @return name:cover type:string default:-- desc:封面
+     */
+
+    public function getRegionRecommend()
+    {
+        $num = input('get.num',2);
+        $list = [];
+        $list[0] = InformationGoods::field('i.id,i.goods_id,g.name,g.low_price,g.cover')
+            ->alias('i')
+            ->leftJoin('StoreGoods g','i.goods_id = g.id')
+            ->order('i.id desc')
+            ->limit(0,$num)
+            ->select()->toArray();
+
+        $list[1] = GiftGoods::field('i.id,i.goods_id,g.name,g.low_price,g.cover')
+        ->alias('i')
+        ->leftJoin('StoreGoods g','i.goods_id = g.id')
+        ->order('i.is_hot desc,id desc')
+        ->limit(0,$num)
+        ->select()->toArray();
+
+        $seckill_act =  SeckillActivity::where([['status','=',1],['end_time','> time',date('Y-m-d H:i:s')],['is_deleted','=',0]])
+            ->order('sort desc,id asc')->limit(0,1)->select()->toArray();
+        if(empty($seckill_act)){
+            $list[2] = [];
+        }else{
+            $list[2] = SeckillGoods::field('i.id,i.goods_id,g.name,g.low_price,g.cover')
+                ->alias('i')
+                ->leftJoin('StoreGoods g','i.goods_id = g.id')
+                ->where('i.act_id',$seckill_act[0]['id'])
+                ->order('id desc')
+                ->limit(0,$num)
+                ->select()->toArray();
+        }
+        $list[3] = StoreGoods::field('id goods_id,name,low_price,cover')->where(['is_deleted'=>0,'status'=>1,'is_presell'=>1])->order('sort desc ,id desc')
+            ->limit(0,$num)->select()->toArray();
+
+        $this->success('ok',['list'=>$list]);
+
+    }
+
+    /**
+     * @title 获取首页我的康养食品(pc)
+     * @desc  获取首页我的康养食品(pc)
+     * @author  qc
+     * @url /api/Mall_index/getBuyInformationGoods
+     * @method GET
+     * @param name:page type:int default:1 desc:页数
+     * @param name:page_num type:int default:20 desc:每页数
+     * @return name:id type:int default:-- desc:记录id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:spec_id type:int default:-- desc:规格id
+     * @return name:goods_name type:srting default:-- desc:商品名称
+     * @return name:cover type:srting default:-- desc:商品图片
+     * @return name:original_price type:float default:-- desc:交易时原价(下划线)
+     * @return name:sell_price type:float default:-- desc:交易价格
+     */
+    public function getBuyInformationGoods()
+    {
+        parent::checkLogin();
+        $order_ids = GoodsOrder::where(['user_id'=>$this->user_id,'pay_state'=>1])->column('id');
+        $list = GoodsOrderItem::field('id,goods_id,goods_name,cover,original_price,sell_price')
+            ->where([['user_id','=',$this->user_id],['belong','=',1],['order_id','in',$order_ids]])
+            ->order('id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取首页资讯
+     * @desc  获取首页资讯
+     * @author  qc
+     * @url /api/Mall_index/getIndexInformation
+     * @method GET
+     * @param name:page type:int default:1 desc:页数
+     * @param name:page_num type:int default:20 desc:每页数
+     * @return name:new_article type:array default:-- desc:最新资讯
+     * @return name:new_article.id type:int default:-- desc:资讯id
+     * @return name:new_article.title type:string default:-- desc:标题
+     * @return name:new_article.type type:int default:-- desc:1文章2视频
+     * @return name:top_article type:array default:-- desc:推荐资讯(数据同new_article)
+     * @return name:hot_article type:array default:-- desc:热门资讯(数据同new_article)
+     */
+    public function getIndexInformation()
+    {
+        $list = [];
+        $article_field = 'id,title,cover,type';
+        // 最新
+        $new_article = InformationArticle::field($article_field)->where(['status'=>1,'is_deleted'=>0])->order('id desc')->find();
+        $list['new_article'] = $new_article ? $new_article->toArray():'';
+        // 推荐
+        $top_article = InformationArticle::field($article_field)->where(['status'=>1,'is_deleted'=>0,'is_top'=>1])->order('id desc')->find();
+        $list['top_article'] = $top_article ? $top_article->toArray():'';
+        // 热门
+        $hot_article = InformationArticle::field($article_field)->where(['status'=>1,'is_deleted'=>0])->order('read_num desc')->find();
+        $list['hot_article'] = $hot_article ? $hot_article->toArray():'';
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+}

+ 159 - 0
application/api/controller/Message.php

@@ -0,0 +1,159 @@
+<?php
+namespace app\api\controller;
+use app\common\model\GoodsOrder;
+use app\common\model\PlatformMessage;
+use app\common\model\PlatformReadLog;
+use app\common\model\SeckillActivity;
+use app\common\model\SeckillGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\UserMessage;
+use library\tools\Data;
+/**
+ * @title 消息管理
+ * @controller Message
+ * @group base
+ */
+class Message extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+
+    /**
+     * @title 获取视频平台消息
+     * @desc  获取视频平台消息
+     * @author  qc
+     * @url /api/Message/getVideoPlatformNews
+     * @method GET
+     * @return name:content type:string default:-- desc:标题
+     * @return name:is_read type:string default:-- desc:是否已读(0否)
+     */
+    public function getVideoPlatformNews()
+    {
+        $video = PlatformMessage::where(['type'=>1])->order('id desc')->find();
+        if(!$video)$this->success('ok',['detail'=>['content'=>'','is_read'=>0]]);
+        $detail =  $video->toArray();
+        $detail['is_read'] =  PlatformReadLog::where(['user_id'=>$this->user_id,'type'=>1,'relation_id'=>$detail['id']])->count();
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+
+    /**
+     * @title 获取交易物流消息(菜单)
+     * @desc  获取交易物流消息
+     * @author  qc
+     * @url /api/Message/getExpressMessageMenu
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:content type:string default:-- desc:内容
+     * @return name:is_read type:int default:-- desc:是否已读(0否)
+     */
+    public function getExpressMessageMenu()
+    {
+        $where[] =  ['user_id','=',$this->user_id];
+        $where[] =  ['type_id','in','2,3'];
+        $detail = UserMessage::where($where)->order('id desc')->find();
+        $this->success('ok',['detail'=>$detail ? $detail->toArray():['content'=>'','is_read'=>0]]);
+    }
+
+
+    /**
+     * @title 获取交易物流消息(内页列表)
+     * @desc  获取交易物流消息(内页列表)
+     * @author  qc
+     * @url /api/Message/getExpressMessageList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:content type:string default:-- desc:内容
+     * @return name:type_id type:int default:-- desc:类型[2发货通知,3收货通知]
+     * @return name:order_info type:array default:-- desc:订单信息
+     * @return name:order_info.id type:int default:-- desc:订单id
+     * @return name:order_info.express_send_no type:string default:-- desc:发货单号
+     * @return name:order_info.order_no type:string default:-- desc:订单号
+     * @return name:goods_list type:array default:-- desc:商品列表
+     * @return name:goods_list.goods_name type:string default:-- desc:商品名
+     * @return name:goods_list.cover type:string default:-- desc:商品图
+     * @return name:goods_list.goods_spec type:string default:-- desc:商品规格
+     */
+    public function getExpressMessageList()
+    {
+        $where[] =  ['user_id','=',$this->user_id];
+        $where[] =  ['type_id','in','2,3'];
+        $list = UserMessage::where($where)
+            ->limit($this->off_set,$this->page_num)
+            ->order('id desc')
+            ->select()->toArray();
+        foreach ($list as &$v) {
+            $v['goods_list'] = StoreGoodsItem::field('goods_name,cover,goods_spec')->where(['order_id'=>$v['relation_id']])->select()->toArray();
+            $v['order_info'] = GoodsOrder::field('id,order_no,express_send_no')->where('id',$v['relation_id'])->find()->toArray();
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取活动平台消息(菜单)
+     * @desc  获取活动平台消息(菜单)
+     * @author  qc
+     * @url /api/Message/getActivityNews
+     * @method GET
+     * @return name:content type:string default:-- desc:标题
+     * @return name:is_read type:string default:-- desc:是否已读(0否)
+     */
+    public function getActivityNews()
+    {
+        $detail = PlatformMessage::where(['type'=>2])->order('id desc')->find();
+        if(!$detail)$this->success('ok',['detail'=>['content'=>'','is_read'=>0]]);
+        $detail =  $detail->toArray();
+        $detail['is_read'] =  PlatformReadLog::where(['user_id'=>$this->user_id,'type'=>2,'relation_id'=>$detail['id']])->count();
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+
+    /**
+     * @title 获取活动平台消息(内页)
+     * @desc  获取活动平台消息(内页)
+     * @author  qc
+     * @url /api/Message/getActivityNewsList
+     * @method GET
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return name:start_time type:string default:-- desc:活动开始时间
+     * @return name:end_time type:string default:-- desc:活动结束时间
+     * @return name:goods_list type:array default:-- desc:商品列表(最多查3个)
+     * @return name:goods_list.name type:string default:-- desc:商品名
+     * @return name:goods_list.cover type:string default:-- desc:商品图
+     */
+    public function getActivityNewsList()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $list = SeckillActivity::where($sel_where)
+            ->field('id,title,cover,start_time,end_time')
+            ->order('id desc')->limit(0,5)->select()->toArray();
+        if(!empty($list)){
+            $relation_id = PlatformMessage::where(['type'=>2])->max('id');// 最新的一条视频推荐
+            Data::save('PlatformReadLog',['user_id'=>$this->user_id,'type'=>2,'relation_id'=>$relation_id,'create_at'=>date('Y-m-d H:i:s')],'user_id',['user_id'=>$this->user_id,'type'=>2,'relation_id'=>$relation_id]);
+        }
+        foreach ($list as &$v){
+            $v['goods_list'] = SeckillGoods::field('g.id,g.name,g.cover')
+                ->alias('s')
+                ->leftJoin('StoreGoods g','g.id = s.goods_id')
+                ->order('s.id desc')
+                ->limit(0,3)
+                ->select()->toArray();
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+
+}

+ 109 - 0
application/api/controller/Nutrition.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace app\api\controller;
+
+use app\common\model\NewsCate;
+use app\common\model\StoreBanner;
+use think\Db;
+
+/**
+ * @title 康养百科(废弃)
+ * @controller Nutrition
+ * @group base
+ */
+class Nutrition extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::setUid();
+    }
+
+    /**
+     * @title 获取营养百科资讯分类
+     * @desc 获取营养百科资讯分类
+     * @author qc
+     * @url /api/Nutrition/getNewsCate
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:logo type:string default:-- desc:log
+     * @return name:title type:string default:-- desc:名称
+     * @return name:pid type:string default:-- desc:上级id
+     * @return name:child_ren type:array default:-- desc:二级分类
+     */
+    public function getNewsCate(){
+        $list  = NewsCate::getCates();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取下级分类
+     * @desc 获取下级分类
+     * @author qc
+     * @url /api/Nutrition/getChildrenCate
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:cate_id type:int default:-- desc:上级id
+     * @return name:logo type:string default:-- desc:log
+     * @return name:title type:string default:-- desc:名称
+     * @return name:pid type:string default:-- desc:上级id
+     * @return name:child_ren type:array default:-- desc:二级分类
+     */
+    public function getChildrenCate()
+    {
+        $cate_id = input('cate_id');
+        $list  = NewsCate::where(['pid'=>$cate_id,'is_deleted'=>0])->field('id,logo,title,pid')->order('sort desc')->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[]]);
+    }
+
+    /**
+     * @title 获取百科轮播图
+     * @desc 获取百科轮播图
+     * @author qc
+     * @url /api/Nutrition/getNutritionBanner
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:cover type:string default:-- desc:图片
+     * @return name:link type:string default:-- desc:链接
+     * @return name:child_ren type:array default:-- desc:二级分类
+     */
+    public function getNutritionBanner()
+    {
+        $list  = StoreBanner::where(['place'=>2,'is_deleted'=>0])
+            ->field('id,cover,link')->order('sort desc')->limit(0,5)->select();
+        $this->success('ok',['list'=>$list? $list->toArray():[]]);
+    }
+
+    /**
+     * @title 获取百科推荐case
+     * @desc 获取百科推荐case
+     * @author qc
+     * @url /api/Nutrition/getNutritionCase
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int default:0 desc:随机查询数量(0查询全部)
+     * @return name:id type:int default:-- desc:id
+     * @return name:title type:string default:-- desc:标题
+     */
+    public function getNutritionCase()
+    {
+        $num = input('get.num',0);
+        $list = Db::name('nutrition_case')->where(['status'=>1])->field('id,title')->select();
+        if(!$list) $this->success('ok',['list'=>[]]);
+        if(!$num || $num > $list) $this->success('ok',['list'=>$list->toArray()]);
+        $rand_key = array_rand(array_keys($list),$num);
+        $list = $list->toArray();
+        $ret = [];
+        array_map(function ($val)use(&$ret,$list){
+            $ret[] = $list[$val];
+        },$rand_key);
+        $this->success('ok',['list'=>$ret]);
+    }
+
+
+
+
+
+
+
+}

+ 1325 - 0
application/api/controller/Order.php

@@ -0,0 +1,1325 @@
+<?php
+namespace app\api\controller;
+use app\common\model\CouponConfig;
+use app\common\model\DiscountActivity;
+use app\common\model\GroupActivity;
+use app\common\model\GroupGoods;
+use app\common\model\GroupGoodsItem;
+use app\common\model\GroupLeader;
+use app\common\model\OrderBill;
+use app\common\model\OrderComment;
+use app\common\model\ReductionActivity;
+use app\common\model\SeckillActivity;
+use app\common\model\SeckillGoods;
+use app\common\model\SeckillGoodsItem;
+use app\common\model\ShoppingTrolley;
+use app\common\model\DeliveryAddress;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\GoodsOrder;
+use app\common\model\GoodsOrderItem;
+use app\common\model\StoreOrderRefund;
+use app\common\model\User;
+use app\common\model\UserCouponList;
+use app\common\model\UserMessage;
+use app\common\model\UserWallet;
+use app\common\service\Activity;
+use app\common\service\ExpressService;
+use app\common\service\OrderCallback;
+use EasyWeChat\Factory;
+use library\tools\Data;
+use think\cache\driver\Redis;
+use think\Db;
+use think\Exception;
+use function EasyWeChat\Kernel\data_get;
+
+/**
+ * @title 订单
+ * @controller Order
+ * @group base
+ */
+class Order extends Base
+{
+    public $int_rate = 100;
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 订单确认页面(立即购买)
+     * @desc  订单确认页面
+     * @author qc
+     * @url /api/Order/confirmOrderImmediately
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:goods_id type:int require:1  default:0 desc:商品id
+     * @param name:spec_id type:int require:1  default:0 desc:商品多规格的规格id
+     * @param name:num type:int default:1 desc:数量
+     * @return name:name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面图
+     * @return name:desc type:string default:-- desc:商品简述(副标题)
+     * @return name:freight_type type:int default:-- desc:运费类型0固定金额,1运费模板
+     * @return name:freight_id type:int default:-- desc:模板id(freight_type=1)
+     * @return name:postage type:float default:-- desc:运费(freight_type=0)
+     * @return name:share_money type:float default:-- desc:分享返利金额
+     * @return name:total_price type:float default:-- desc:订单金额
+     * @return name:total_group type:float default:-- desc:拼团订单金额
+     * @return name:total_seckill type:float default:-- desc:秒杀订单金额
+     * @return name:total_discount type:float default:-- desc:折扣订单金额
+     * @return name:item_list type:array default:-- desc:商品多规格列表
+     * @return name:item_list.spec_info type:array default:-- desc:规格型号设置;
+     * @return name:item_list.goods_no type:string default:-- desc:规格货号
+     * @return name:item_list.goods_title:string default:-- desc:规格标题
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.stock type:int default:-- desc:剩余库存
+     * @return name:item_list.original_price type:float default:-- desc:原价
+     * @return name:item_list.sell_price type:float default:-- desc:售价
+     * @return name:item_list.seckill_price type:float default:-- desc:秒杀价(没有秒杀活动=售价)
+     * @return name:item_list.group_price type:float default:-- desc:拼团价(没有拼团活动=售价)
+     * @return name:item_list.discount_price type:float default:-- desc:折扣价(没有折扣活动=售价)
+     * @return name:discount type:array default:-- desc:折扣活动详情(为空:商品没有正在进行的折扣活动)
+     * @return name:seckill type:array default:-- desc:秒杀活动详情(为空:商品没有正在进行的秒杀活动)
+     * @return name:seckill.start_time type:string default:-- desc:开始时间
+     * @return name:seckill.end_time type:string default:-- desc:结束时间
+     * @return name:group type:array default:-- desc:拼团活动
+     * @return name:group.start_time type:string default:-- desc:开始时间
+     * @return name:group.end_time type:string default:-- desc:结束时间
+     * @return name:group.full_num type:int default:-- desc:成团人数
+     * @return name:reduction type:array default:-- desc:满减活动
+     * @return name:reduction.id type:int default:-- desc:满减活动id
+     * @return name:reduction.title type:string default:-- desc:满减标题
+     * @return name:reduction.start_time type:string default:-- desc:满减开始时间
+     * @return name:reduction.end_time type:string default:-- desc:满减结束时间
+     * @return name:reduction.act_set type:array default:-- desc:满减设置
+     * @return name:reduction.act_set.full type:float default:-- desc:满多少
+     * @return name:reduction.act_set.reduction type:float default:-- desc:减多少
+     * @return name:goods_discount type:array default:-- desc:商品优惠
+     * @return name:goods_discount.order_cash type:float default:-- desc:积分最高抵扣订单金额
+     * @return name:goods_discount.coupon_list type:array default:-- desc:优惠券列表(单品可以只让用一张)
+     * @return name:coupon_list.id type:int default:-- desc:优惠券列表id
+     * @return name:coupon_list.low_amount type:float default:-- desc:订单最低金额
+     * @return name:coupon_list.amount type:float default:-- desc:可抵扣金额
+     * @return name:add_info type:array default:-- desc:默认收货地址(设置才有)
+     * @return name:add_info.pro_id type:int   default:-- desc:省id
+     * @return name:add_info.city_id type:int   default:-- desc:市id
+     * @return name:add_info.county_id type:int  default:-- desc:县区id
+     * @return name:add_info.pro_name type:string  default:-- desc:省名
+     * @return name:add_info.city_name type:string  default:-- desc:市名
+     * @return name:add_info.county_name type:string  default:-- desc:县区名
+     * @return name:add_info.street_name type:string  default:-- desc:街道名称
+     * @return name:add_info.detail type:string  default:-- desc:详细地址
+     * @return name:add_info.phone type:string  default:-- desc:联系电话
+     * @return name:add_info.name type:string   default:-- desc:联系人
+     *
+     */
+    public function confirmOrderImmediately()
+    {
+        $user_id = $this->user_id;
+        $goods_id = input('get.goods_id');
+        $spec_id = input('get.spec_id');
+        $num = input('get.num',1);
+        $act_type = input('get.act_type',0);
+        $act_id = input('get.act_id',0);
+        $field = 'id,name,cover,desc,low_price,status,is_deleted,level_set,freight_type,postage';
+        $goods_info = StoreGoods::with(['itemList'=>function($query)use($spec_id){
+            return $query->where('id',$spec_id);
+        }])->field($field)->where('id',$goods_id)->find()->toArray();
+        $act_data = Activity::goodsActivityList($goods_id);
+        $goods_info['item_list'] =  $goods_info['item_list'][0];
+        // 秒杀价格
+        $goods_info['item_list']['seckill_price'] =  $goods_info['item_list']['sell_price'];
+        if(!empty($act_data['seckill']['goods'])){
+            foreach ($act_data['seckill']['goods']['item'] as $sv){
+                if($sv['spec_id'] ==  $spec_id){
+                    $goods_info['item_list']['seckill_price'] = $sv['seckill_price'];
+                    break;
+                }
+            }
+        }
+        // 拼团价格
+        $goods_info['item_list']['group_price'] =  $goods_info['item_list']['sell_price'];
+        if(!empty($act_data['group']['goods'])){
+            foreach ($act_data['group']['goods']['item'] as $gv){
+                if($gv['spec_id'] ==  $spec_id){
+                    $goods_info['item_list']['group_price'] = $gv['group_price'];
+                    break;
+                }
+            }
+        }
+        // 折扣活动
+        $goods_info['item_list']['discount_price'] =  $goods_info['item_list']['sell_price'];
+        if(!empty($act_data['discount']['act'])){
+            $goods_info['item_list']['discount_price'] = bcmul($goods_info['item_list']['sell_price'],$act_data['discount']['act']['discount']/100,2);
+        }
+
+
+        $level_set = $goods_info['level_set'] ? json_decode($goods_info['level_set'],true):[];
+        // 商品优惠信息
+        $goods_discount = [
+            'order_cash' => 0,
+            'express_cash' => 0,
+            'coupon_list'=> [],
+        ];
+        $user_info = User::field('u.id,u.level_id,w.integral,money')->alias('u')
+            ->leftJoin('UserWallet w','u.id = w.user_id')
+            ->where('u.id',$this->user_id)->find()->toArray();
+        if($user_info['level_id'] > 0 && !empty($level_set))
+        {
+            $goods_discount['order_cash'] = isset($level_set[$user_info['level_id']]) ? $level_set[$user_info['level_id']]['integral_cash']:0;
+           // $goods_discount['express_cash'] = isset($level_set[$user_info['level_id']]) ? $level_set[$user_info['level_id']]['integral_freight']:0;
+        }
+        // 优惠券   全场限时 || 全场不限时 || 商品券限时 || 商品券不限时
+        $goods_discount['coupon_list'] = UserCouponList::where(function ($query)use($goods_id,$user_id){
+            return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',0],['type','=',1],['end','> time',date('Y-m-d')],['start','< time',date('Y-m-d')]]);
+        })->whereOr(function ($query)use($goods_id,$user_id){
+            return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',0],['type','=',0]]);
+        })->whereOr(function ($query)use($goods_id,$user_id){
+            return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',1],['goods_id','=',$goods_id]]);
+        })->select()->toArray();
+        $goods_info['total_price']= bcmul($goods_info['item_list']['sell_price'],$num,2);
+        $goods_info['total_seckill']= bcmul($goods_info['item_list']['seckill_price'],$num,2);
+        $goods_info['total_group']= bcmul($goods_info['item_list']['group_price'],$num,2);
+        $goods_info['total_discount']= bcmul($goods_info['item_list']['discount_price'],$num,2);
+        $add_info = DeliveryAddress::where(['user_id'=>$this->user_id,'is_mr'=>1])->find();
+        $this->success('ok',['goods_info'=>$goods_info,
+            'seckill'=>$act_data['seckill']['act'],
+            'group'=>$act_data['group']['act'],
+            'discount'=>$act_data['discount']['act'],
+            'goods_discount'=>$goods_discount,
+            'user_info'=>$user_info,
+            'reduction'=>ReductionActivity::getAct(),
+            'add_info' =>$add_info ? $add_info->toArray():'',
+        ]);
+    }
+
+    /**
+     * @title 生成订单(立即购买)
+     * @desc  立即购买场景
+     * @author  qc
+     * @url /api/Order/createOrderImmediately
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:goods_id type:int require:1  default:0 desc:商品id
+     * @param name:spec_id type:int require:1  default:0 desc:商品多规格的规格id
+     * @param name:num type:int default:1 desc:数量
+     * @param name:act_type type:int default:0 desc:活动类型(0正常购买,1限时秒杀(抢购),2拼团,3折扣)
+     * @param name:act_id type:int default:0 desc:活动id(活动类型act_type>0必传)
+     * @param name:leader_id type:int default:0 desc:参与团的id(为0是新开团)
+     * @param name:share_user type:int default:0 desc:分享人(谁分享给你的)
+     * @param name:integral_order type:int default:0 desc:积分(抵扣订单的)
+     * @param name:coupon_id type:int default:0 desc:优惠券id
+     * @param name:add_id type:int default:1 desc:收货地址id
+     * @param name:pay_city type:int default:0 desc:本次登录的城市
+     * @return name:order_id type:int default:1 desc:订单id
+     */
+    public function createOrderImmediately()
+    {
+        $goods_id = input('post.goods_id');
+        $spec_id = input('post.spec_id');
+        $num = input('post.num');
+        $add_id = input('post.add_id');
+        $act_type = input('post.act_type',0);
+        $act_id = input('post.act_id',0);
+        $share_user = input('post.share_user',0);
+        $integral_order = input('post.integral_order',0);
+        $integral_express = input('post.integral_express',0);
+        $coupon_id = input('post.coupon_id',0);// 优惠券id
+        $leader_id = input('post.leader_id',0);// 参与拼团的id
+        if(!$goods_id || !$spec_id)  $this->error('请选择商品');
+        if($num <=0 ) $this->error('数量有误');
+        if(!$add_id ) $this->error('请选择收货地址');
+        Db::startTrans();
+        try {
+            $add_info = DeliveryAddress::find($add_id)->toArray();
+            $order_insert = [
+                'user_id' => $this->user_id,
+                'order_no' => get_order_sn(),
+                'goods_num' => $num,
+                'pro_name' => $add_info['pro_name'],
+                'city_name' => $add_info['city_name'],
+                'county_name' => $add_info['county_name'],
+                'street_name' => $add_info['street_name'],
+                'user_name' => $add_info['name'],
+                'add_detail' => $add_info['detail'],
+                'phone' => $add_info['phone'],
+                'act_type' => $act_type,
+                'act_id' => $act_id,
+                'share_user' => $share_user,
+                'leader_id' => $leader_id,
+                'cl_ids' => $coupon_id,
+                'express_cash' => 0,
+                'coupon_cash' => 0,
+            ];
+
+            $goods_info = StoreGoods::with(['itemList'=>function($query)use($spec_id){
+                return $query->where('id',$spec_id)->where('is_deleted',0);
+            }])->where('id',$goods_id)->where('is_deleted',0)->where('status',1)->find();
+            if(!$goods_info) throw new Exception('商品已下架');
+            $goods_info = $goods_info->toArray();
+            if(empty($goods_info['item_list'])) throw new Exception('该规格已下架');
+            if($goods_info['item_list'][0]['stock'] < $num) throw new Exception('库存不足');
+            $order_insert['original_price'] = bcmul($num,$goods_info['item_list'][0]['original_price'],2);// 原价
+            $true_cost = $goods_info['item_list'][0]['sell_price'];//实际售价
+            $spec_info = $goods_info['item_list'][0];
+            // 秒杀购买
+            if($act_type == 1){
+                if(!$act_id) $this->exception('参数错误');
+                $act_info = SeckillActivity::where('id',$act_id)->find()->toArray();
+                if($act_info['status'] != 1 || $act_info['is_deleted'] == 1 || strtotime($act_info['end_time'])<time()) $this->exception('活动已结束');
+                if(strtotime($act_info['start_time']) > time()) $this->exception('活动尚未开始请耐心等待');
+                // 商品详情
+                $seckill_goods_id = SeckillGoods::where(['goods_id'=>$goods_id,'act_id'=>$act_id])->value('id');
+                if(!$seckill_goods_id) $this->exception('商品信息错误');
+                $item = SeckillGoodsItem::where(['act_id'=>$act_id,'goods_id'=>$goods_id,'spec_id'=>$spec_id])->find()->toArray();
+                if($item['status'] != 1) $this->exception('商品已下架');
+                // redis 验证库存
+                // $redis_prefix = 'SECKILL_'.$act_id.'_'.$item['id'];
+                // $redis = new Redis();
+                //$redis_stock = $redis->get($redis_prefix.'_stock',0);
+                // if($redis_stock <= 0 || $redis_stock < $num || $item['stock'] < $num) $this->exception('库存不足');
+                //$redis->dec($redis_prefix.'_stock',$num);// 扣减redis库存
+                $true_cost = $item['seckill_price'];
+            }
+            //拼团购买
+            if($act_type == 2){
+                if(!$act_id) $this->exception('参数错误');
+                $act_info = GroupActivity::where('id',$act_id)->find()->toArray();
+                if($act_info['status'] != 1 || $act_info['is_deleted'] == 1 || strtotime($act_info['end_time'])<time()) $this->exception('活动已结束');
+                if(strtotime($act_info['start_time']) > time()) $this->exception('活动尚未开始请耐心等待');
+                $group_goods_id = GroupGoods::where(['goods_id'=>$goods_id,'act_id'=>$act_id])->value('id');
+                if(!$group_goods_id) $this->exception('商品信息错误');
+                $item = GroupGoodsItem::where(['act_id'=>$act_id,'goods_id'=>$goods_id,'spec_id'=>$spec_id])->find()->toArray();
+                if($item['status'] != 1) $this->exception('商品已下架');
+                // redis 验证库存
+               /* $redis_prefix = 'GROUP_'.$act_id.'_';
+                $redis = new Redis();
+                $redis_stock = $redis->get($redis_prefix.$item['id'].'_stock',0);
+                if($redis_stock <= 0 || $redis_stock < $num || $item['stock'] < $num) $this->exception('库存不足');
+                */
+               if($leader_id){
+                   // if($redis->get($redis_prefix.$leader_id,0)) $this->exception('该团已有团员参与');
+                   // $redis->set($redis_prefix.$leader_id,1);
+                    GroupLeader::where(['id'=>$leader_id])->update(['status'=>3]);
+                }
+               // $redis->dec($redis_prefix.'_stock',$num);// 扣减redis库存
+                $true_cost = $item['group_price'];
+
+            }
+            // 折扣购买
+            if($act_type == 3){
+                if(!$act_id) $this->exception('参数错误');
+                $act_info = DiscountActivity::where('id',$act_id)->find()->toArray();
+                if($act_info['status'] != 1 || $act_info['is_deleted'] == 1 || strtotime($act_info['end_time'])<time()) $this->exception('活动已结束');
+                if(strtotime($act_info['start_time']) > time()) $this->exception('活动尚未开始请耐心等待');
+                $true_cost = bcmul($goods_info['item_list'][0]['sell_price'] , $act_info['discount']/100,2);
+            }
+            $price_goods   =  bcmul($num,$true_cost,2); // 需要支付商品价格
+            // 积分抵扣金额
+            $total_integral = $integral_order + $integral_express;// 积分使用数量
+            if($total_integral > 0){
+                $wallet_integral = UserWallet::where(['user_id'=>$this->user_id])->value('integral');
+                if($total_integral > $wallet_integral) $this->exception('积分不足');
+            }
+            $integral_cash  = bcdiv($total_integral,$this->int_rate,2);// 积分抵扣订单金额(全部)
+            if($integral_express >0) $order_insert['express_cash'] =  bcdiv($integral_express,$this->int_rate,2);// 积分抵扣运费金额
+            // 优惠券
+            if($coupon_id){
+                $coupon_info = UserCouponList::where(function ($query)use($coupon_id){
+                    return  $query->where([['id','=',$coupon_id],['status','=',0],['coupon_type','=',0],['type','=',1],['end','> time',date('Y-m-d')],['start','< time',date('Y-m-d')]]);
+                })->whereOr(function ($query)use($coupon_id){
+                    return  $query->where([['id','=',$coupon_id],['status','=',0],['coupon_type','=',0],['type','=',0]]);
+                })->whereOr(function ($query)use($goods_id,$coupon_id){
+                    return  $query->where([['id','=',$coupon_id],['status','=',0],['coupon_type','=',1],['goods_id','=',$goods_id],['type','=',1],['end','> time',date('Y-m-d')],['start','< time',date('Y-m-d')]]);
+                })->whereOr(function ($query)use($goods_id,$coupon_id){
+                    return  $query->where([['id','=',$coupon_id],['status','=',0],['coupon_type','=',1],['goods_id','=',$goods_id],['type','=',0]]);
+                })->find();
+                if(!$coupon_info) $this->exception('优惠券过期');
+                if($coupon_info->low_amount < $price_goods) $this->exception('优惠券使用限制');
+                UserCouponList::where('id',$coupon_id)->update(['status'=>1]);
+                $order_insert['cl_ids'] =  $coupon_id;
+                $order_insert['coupon_cash'] =  $coupon_info->amount;   // 优惠券抵扣金额
+            }
+            // 获取运费信息
+            $exp_data = ExpressService::getGoodsExpressPrice($goods_info,$add_info,$num);
+            if($exp_data['code'] != 200 ) throw  new Exception($exp_data['msg']);
+            $price_express =  $exp_data['freight']; //  商品运费
+            if($price_express < $order_insert['express_cash'] ) $this->exception('运费抵扣金额有误');
+            $redu_money  = ReductionActivity::getReduction($price_goods);// 商品满减
+            $total_discount = $integral_cash + $order_insert['coupon_cash'] + $redu_money;
+            //订单金额 =  商品金额 + 运费 - (积分抵扣 + 优惠券 + 满减)
+            $order_money = bcsub($price_goods+$price_express,$total_discount ,2);
+            if($order_money < 0) $this->exception('订单金额有误');
+            $order_insert['price_total'] = $order_money;
+            $order_insert['price_goods'] = $price_goods;
+            $order_insert['price_express'] = $price_express;
+            $order_insert['integral']  = $total_integral;
+            $order_insert['total_discount'] = $total_discount ;
+            $order_insert['redu_money'] = $redu_money;
+            $order_info = GoodsOrder::create($order_insert);
+            // 扣除积分
+            if($total_integral) UserWallet::userIntegralChange($this->user_id,$total_integral,'订单抵扣',1,-1,$order_info->id);
+            $order_item = [
+                'user_id' => $this->user_id,
+                'order_id' => $order_info->id,
+                'goods_id' => $goods_id,
+                'goods_no' => $spec_info['goods_no'],
+                'goods_spec' => $spec_info['goods_spec'],
+                'goods_name' => $goods_info['name'],
+                'spec_title' => $spec_info['spec_title'],
+                'spec_id' => $spec_info['id'],
+                'is_combo' => $goods_info['is_combo'],
+                'cover' => $goods_info['cover'],
+                'original_price' => $spec_info['original_price'],
+                'sell_price' => $true_cost,
+                'pay_price' => $order_money,
+                'num' => $num,
+                'belong' => StoreGoods::getGoodsBelong($goods_id),
+            ];
+            GoodsOrderItem::create($order_item);
+            StoreGoods::where('id',$goods_id)->setDec('stock',$num);
+            StoreGoodsItem::where('id',$spec_id)->setDec('stock',$num);
+       /*     switch ($act_type){
+                case 0: // 商城购买
+                    StoreGoods::where('id',$goods_id)->setDec('stock',$num);
+                    StoreGoodsItem::where('id',$spec_id)->setDec('stock',$num);
+                    break;
+                case 1:  // 秒杀购买
+                    SeckillGoodsItem::where('id',$item['id'])->setDec('stock',$num);
+                    break;
+                case 2:// 拼团购买
+                    GroupGoodsItem::where('id',$item['id'])->setDec('stock',$num);
+                    break;
+            }*/
+            Db::commit();
+        }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg = $e->getMessage();
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('添加成功',['order_id'=>$order_info->id]):$this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 订单支付
+     * @desc  订单支付
+     * @author  qc
+     * @url /api/Order/payOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:pay_type type:int require:1  default:0 desc:支付方式(1微信小程序 ,2佣金余额 ,3移动支付(支付宝),4移动支付(微信),5pc(微信扫码),6pc(支付宝扫码))
+     * @return name:config type:array default:0 desc:小程序支付配置
+     * @return name:config.appId type:string default:-- desc:公众账号ID(小程序支付)
+     * @return name:config.signType type:string default:-- desc:签名类型(小程序支付)
+     * @return name:config.paySign type:string default:-- desc:签名(小程序支付)
+     * @return name:config.nonceStr type:string default:-- desc:随机字符串(小程序支付&&APP支付)
+     * @return name:config.timestamp type:string default:-- desc:时间戳小程序支付&&APP支付)
+     * @return name:config.partnerid type:string default:-- desc:商户号(App支付)
+     * @return name:config.prepayid type:string default:-- desc:唯一支付号(App支付)
+     * @return name:config.package type:string default:-- desc:package(App支付)
+     * @return name:config.sign type:string default:-- desc:签名(App支付)
+     * @return name:code_url type:string default:-- desc:付款码url
+     */
+    public function payOrder()
+    {
+        $order_id = input('post.order_id');
+        $pay_type = input('post.pay_type');
+        $order_info = GoodsOrder::with('orderItem')->where('id',$order_id)->find()->toArray();
+        if($order_info['status'] != 0) $this->error('订单状态错误');
+        if($order_info['cancel_state'] != 0 || $order_info['is_deleted'] != 0) $this->error('订单异常');
+        if($order_info['price_total'] <= 0) $this->error('订单金额错误');
+        $pay_no  = $order_info['pay_no'] ? $order_info['pay_no'] : get_order_sn();// 支付单号
+        if(!$order_info['pay_no']) GoodsOrder::where('id',$order_id)->update(['pay_no'=>$pay_no]);
+        $user_info = User::with('wallet')->where('id',$this->user_id)->find()->toArray();
+        $ret_data = ['pay_status'=>0,'config'=>[],'code_url'=>''];
+        Db::startTrans();
+        try {
+            switch ($pay_type){
+                case 1://微信小程序
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/goodsOrderNotify';
+                    $pay_config = WeChatPay::wxPay('订单支付',$pay_no,$order_info['price_total'],$notify_url,'JSAPI',$user_info['openid']);
+                    if($pay_config['code'] != 200) $this->exception($pay_config['msg']);
+                    $ret_data['config'] = $pay_config['config'];
+                    break;
+                case 2://佣金余额
+                    if($user_info['wallet']['money'] < $order_info['price_total'])$this->exception('余额不足');
+                    // 扣除余额
+                    UserWallet::userMoneyChange($this->user_id,$order_info['price_total'],'订单支付',1,-1,$order_id);
+                    // 支付完成后回调
+                    $back_res = OrderCallback::goodsOrderCallBack($order_info,$pay_type);
+                    if(!$back_res['ret_val']) $this->exception($back_res['msg']);
+                    $ret_data['pay_status'] = 1;
+                    break;
+
+                case 3://移动支付(支付宝)
+                    break;
+                case 4:  //4移动支付(微信)
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/goodsOrderNotify';
+                    $pay_config = WeChatPay::wxPay('订单支付',$pay_no,$order_info['price_total'],$notify_url,'APP');
+                    if($pay_config['code'] != 200) $this->exception($pay_config['msg']);
+                    $ret_data['config'] = $pay_config['config'];
+                    break;
+                case 5: //pc(微信扫码)
+                    $notify_url = $this->request->root(true) . '/api/we_chat_pay/goodsOrderNotify';
+                    $app = Factory::payment(config('app.wx_pay'));
+                    $result = $app->order->unify([
+                        'body' => '微信扫码支付',
+                        'out_trade_no' => $pay_no,
+                        'total_fee' => $order_info['price_total'] * 100,
+                        'notify_url' => $notify_url, // 支付结果通知网址,如果不设置则会使用配置里的默认地址
+                        'trade_type' => 'NATIVE', // 请对应换成你的支付方式对应的值类型
+                    ]);
+                    if(!isset($result['code_url'])) $this->exception($result['err_code_des']?$result['err_code_des']:'获取付款码失败');
+                    $ret_data['code_url'] = $result['code_url'];
+                    break;
+                case 6: //pc(支付宝扫码)
+                    break;
+            }
+
+            Db::commit();
+        }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg =  $e->getMessage();
+            Db::rollback();
+        }
+        $this->transReturn($ret_data);
+    }
+
+    /**
+     * @title 订单确认页面(购物车)
+     * @desc  订单确认页面
+     * @author qc
+     * @url /api/Order/confirmOrderByTrolley
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:ids type:int require:1  default:0 desc:购物车记录id
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_name type:string default:-- desc:商品名称
+     * @return name:cover type:string default:-- desc:商品封面
+     * @return name:goods_status type:int default:-- desc:商品状态(1上架,0下架)
+     * @return name:total_price type:float default:-- desc:该商品价格(这个商品下面所有规格商品)
+     * @return name:integral_cash type:float default:-- desc:该商品积分可抵扣金额
+     * @return name:deleted_status type:string default:-- desc:删除状态(1删除,0未删除)
+     * @return name:item_list type:array default:-- desc:添加该商品的规格列表
+     * @return name:item_list.id type:int default:-- desc:购物车记录id
+     * @return name:item_list.num type:int default:-- desc:数量
+     * @return name:item_list.goods_id type:int default:-- desc:商品id
+     * @return name:item_list.spec_id type:int default:-- desc:规格id
+     * @return name:item_list.goods_no type:string default:-- desc:货号
+     * @return name:item_list.spec_title type:string default:-- desc:规格名称
+     * @return name:item_list.sell_price type:flaot default:-- desc:售价
+     * @return name:item_list.original_trolley type:flaot default:-- desc:规格总原价(下划线用[原价*数量])
+     * @return name:item_list.sell_trolley type:flaot default:-- desc:规格总价(售价*数量)
+     * @return name:item_list.original_price type:float default:-- desc:规格原价(下划线价格)
+     * @return name:item_list.sell_price type:float default:-- desc:规格售价
+     * @return name:coupon_list type:array default:-- desc:满减券
+     * @return name:coupon_list.title type:string default:-- desc:满减券标题
+     * @return name:coupon_list.low_amount type:float default:-- desc:最低消费金额
+     * @return name:coupon_list.amount type:float default:-- desc:抵扣金额
+     * @return name:order_money type:float default:-- desc:订单商品金额(不含运费)
+     * @return name:total_integral_money type:float default:-- desc:积分可抵扣金额(订单最高)
+     * @return name:reduction type:array default:-- desc:满减活动
+     * @return name:reduction.id type:int default:-- desc:满减活动id
+     * @return name:reduction.title type:string default:-- desc:满减标题
+     * @return name:reduction.start_time type:string default:-- desc:满减开始时间
+     * @return name:reduction.end_time type:string default:-- desc:满减结束时间
+     * @return name:reduction.act_set type:array default:-- desc:满减设置
+     * @return name:reduction.act_set.full type:float default:-- desc:满多少
+     * @return name:reduction.act_set.reduction type:float default:-- desc:减多少
+     * @return name:redu_money type:float default:-- desc:满减金额
+     * @return name:add_info type:array default:-- desc:默认收货地址(设置才有)
+     * @return name:add_info.pro_id type:int   default:-- desc:省id
+     * @return name:add_info.city_id type:int   default:-- desc:市id
+     * @return name:add_info.county_id type:int  default:-- desc:县区id
+     * @return name:add_info.pro_name type:string  default:-- desc:省名
+     * @return name:add_info.city_name type:string  default:-- desc:市名
+     * @return name:add_info.county_name type:string  default:-- desc:县区名
+     * @return name:add_info.street_name type:string  default:-- desc:街道名称
+     * @return name:add_info.detail type:string  default:-- desc:详细地址
+     * @return name:add_info.phone type:string  default:-- desc:联系电话
+     * @return name:add_info.name type:string   default:-- desc:联系人
+     */
+    public function confirmOrderByTrolley()
+    {
+        $ids  = input('get.ids');
+        $user_id = $this->user_id;
+        // 购物车数据分组
+        $trolley_goods = ShoppingTrolley::field('goods_id')->where('user_id',$this->user_id)->where('id','in',$ids)->group('goods_id')->select();
+        $goods_ids = array_column($trolley_goods->toArray(),'goods_id');
+        // 用户等级&&积分
+        $user_info = User::field('u.id,u.level_id,w.integral,money')->alias('u')
+            ->leftJoin('UserWallet w','u.id = w.user_id')
+            ->where('u.id',$this->user_id)->find()->toArray();
+
+        $list = [];
+        $field = 'id,name,cover,status,is_deleted,is_combo,level_set';
+        $goods_list = StoreGoods::field($field)->where('id','in',$goods_ids)->select()->toArray();
+        $total_integral_money = 0;
+        $order_money = 0;// 订单商品金额
+        foreach ($goods_list as $goods_info){
+            $trolley_data = ['goods_id'=>$goods_info['id'],'cover'=>$goods_info['cover'],'goods_name'=>$goods_info['name'],'goods_status'=>$goods_info['status'],'deleted_status'=>$goods_info['is_deleted'],'is_combo'=>$goods_info['is_combo']];
+            $level_set = $goods_info['level_set'] ? json_decode($goods_info['level_set'],true):[];
+            $join_field = 't.id,t.num,t.spec_id,t.goods_id,i.goods_spec,i.goods_no,i.spec_title,i.stock,i.is_deleted,i.original_price,i.sell_price,i.weight';
+            $item_list = ShoppingTrolley::field($join_field)->alias('t')
+                ->where('t.goods_id',$goods_info['id'])->where('t.id','in',$ids)
+                ->leftJoin('StoreGoodsItem i','i.id = t.spec_id')
+                ->select()->toArray();
+            foreach ($item_list as &$item) {
+                $item['original_trolley'] = bcmul($item['num'],$item['original_price'],2);// 下划线价格
+                $item['sell_trolley'] = bcmul($item['num'],$item['sell_price'],2);// 售价
+            }
+            $trolley_data['total_price'] =array_sum(array_column($item_list,'sell_trolley'));// 该商品总价格
+            $trolley_data['item_list'] = $item_list;
+            $order_money = $order_money +  $trolley_data['total_price'];
+            // 商品券
+            /*$trolley_data['goods_coupon'] =  UserCouponList::field('id,title,low_amount,type,coupon_type')->where(function ($query)use($goods_info,$user_id){
+                return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',1],['goods_id','=',$goods_info['id']],['type','=',1],['end','> time',date('Y-m-d')],['start','< time',date('Y-m-d')]]);
+            })->whereOr(function ($query)use($goods_info,$user_id){
+                return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',1],['goods_id','=',$goods_info['id']],['type','=',0]]);
+            })->select()->toArray();*/
+            $goods_num = array_sum(array_column($item_list,'num'));
+            if($user_info['level_id'] > 0 && !empty($level_set)) {
+                $trolley_data['integral_cash'] = isset($level_set[$user_info['level_id']]) ? $level_set[$user_info['level_id']]['integral_cash']:0;
+                $total_integral_money = bcadd($total_integral_money, $trolley_data['integral_cash'] ,2);
+            }
+            $list[] = $trolley_data;
+        }
+        $coupon_list = UserCouponList::field('id,title,low_amount,amount,type,coupon_type')->where(function ($query)use($user_id){
+            return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',0],['type','=',1],['end','> time',date('Y-m-d')],['start','< time',date('Y-m-d')]]);
+        })->whereOr(function ($query)use($user_id){
+            return  $query->where([['user_id','=',$user_id],['status','=',0],['coupon_type','=',0],['type','=',0]]);
+        })->select()->toArray();
+        $redu_money  = ReductionActivity::getReduction($order_money);
+        $add_info = DeliveryAddress::where(['user_id'=>$this->user_id,'is_mr'=>1])->find();
+        $this->success('ok',[
+            'list'=>$list,
+            'coupon_list'=>$coupon_list,
+            'order_money'=>$order_money,
+            'total_integral_money'=>$total_integral_money,
+            'reduction' => ReductionActivity::getAct(),
+            'redu_money' => $redu_money,
+            'add_info' => $add_info ? $add_info->toArray():'',
+        ]);
+    }
+
+    /**
+     * @title 生成订单(购物车[活动没有购物车])
+     * @desc  购物车场景
+     * @author  qc
+     * @url /api/Order/createOrderByTrolley
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:ids type:int require:1  default:0 desc:购物车记录id
+     * @param name:add_id type:int default:1 desc:收货地址id
+     * @param name:coupon_ids type:int default:1 desc:使用优惠券id(多个用逗号隔开)
+     * @param name:total_integral type:int default:0 desc:使用积分数量
+     * @param name:pay_city type:int default:0 desc:本次登录的城市
+     * @return name:order_id type:int default:1 desc:订单id
+     */
+    public function createOrderByTrolley()
+    {
+        $ids  = input('post.ids');
+        $add_id = input('post.add_id');
+        $coupon_ids = input('post.coupon_ids');
+        $total_integral = input('post.total_integral');
+        if(!$ids) $this->error('请选择商品');
+        if(!$add_id ) $this->error('请选择收货地址');
+        $ret_data = ['order_id'=>0];
+        Db::startTrans();
+        try{
+            $add_info = DeliveryAddress::where('id',$add_id)->find()->toArray();
+            $trolley_list = ShoppingTrolley::with(['goodsSpec','goodsInfo'])->where('id','in',$ids)->select()->toArray();
+            if(empty($trolley_list)) $this->exception('购物车记录有误');
+            // 计算运费
+            $price_express = 0;// 总运费
+            $goods_list = ShoppingTrolley::where('id','in',$ids)->field('goods_id,sum(num) as total_num')->group('goods_id')->select()->toArray();
+            foreach ($goods_list as $v){
+                $goods_info = StoreGoods::field('name,freight_type,freight_id,postage')->where('id',$v['goods_id'])->find()->toArray();
+                $freight_data = ExpressService::getGoodsExpressPrice($goods_info,$add_info,$v['total_num']);
+                if($freight_data['code'] != 200){
+                    $this->exception($goods_info['name'].$freight_data['msg']);
+                    break;
+                }
+                $price_express += $freight_data['freight'];
+            }
+            // 计算运费 end
+            $price_goods =  0; // 商品总金额
+            $original_total = 0; // 商品总原价
+            $total_num = 0;// 商品总数量
+            $order_item = [];// 订单列表
+            foreach ($trolley_list as $trolley)
+            {
+                $price_goods += $trolley['num'] * $trolley['goods_spec']['sell_price'];
+                $original_total += $trolley['num'] * $trolley['goods_spec']['original_price'];
+                $total_num +=$trolley['num'];
+                $order_item[] = [
+                    'user_id' => $this->user_id,
+                    'goods_id' => $trolley['goods_id'],
+                    'goods_no' => $trolley['goods_spec']['goods_no'],
+                    'goods_name' => $trolley['goods_info']['name'],
+                    'goods_spec' => $trolley['goods_spec']['goods_spec'],
+                    'spec_title' => $trolley['goods_spec']['spec_title'],
+                    'spec_id' => $trolley['spec_id'],
+                    'is_combo' =>  $trolley['goods_info']['is_combo'],
+                    'cover' =>  $trolley['goods_info']['cover'],
+                    'original_price' => $trolley['goods_spec']['original_price'],
+                    'sell_price' => $trolley['goods_spec']['sell_price'],
+                    'num' => $trolley['num'],
+                    'trolley_id' => $trolley['id'],
+                    'belong' => StoreGoods::getGoodsBelong($trolley['goods_id']),
+                ];
+            }
+            $order_insert = [
+                'user_id' => $this->user_id,
+                'order_no' => get_order_sn(),
+                'goods_num' => $total_num,
+                'pro_name' => $add_info['pro_name'],
+                'city_name' => $add_info['city_name'],
+                'county_name' => $add_info['county_name'],
+                'street_name' => $add_info['street_name'],
+                'user_name' => $add_info['name'],
+                'add_detail' => $add_info['detail'],
+                'phone' => $add_info['phone'],
+                'integral' => $total_integral,
+                'int_cash' => 0,
+                'cl_ids' => $coupon_ids,
+                'coupon_cash' => 0,
+            ];
+            // 积分抵扣金额
+            if($total_integral > 0){
+                $wallet_integral = UserWallet::where(['user_id'=>$this->user_id])->value('integral');
+                if($total_integral > $wallet_integral) $this->exception('积分不足');
+                $order_insert['int_cash'] = bcdiv($total_integral,$this->int_rate,2);// 积分抵扣订单金额(全部)
+            }
+
+            if($coupon_ids){
+                $coupon_list = CouponConfig::field('id,low_amount,amount')->where('id','in',$coupon_ids)
+                    ->where('status','=','0')->order('low_amount desc')->select()->toArray();
+                if($price_goods < $coupon_list[0]['low_amount']) $this->exception('订单金额最低:'. $coupon_list[0]['low_amount']);
+                $order_insert['coupon_cash'] = array_sum(array_column($coupon_list,'amount'));
+            }
+            if($price_goods < $order_insert['int_cash']+$order_insert['coupon_cash']) $this->exception('订单金额有误');
+            $redu_money = ReductionActivity::getReduction($price_goods);// 商品满减金额
+            $total_discount = $order_insert['int_cash'] + $order_insert['coupon_cash']+$redu_money;
+            $price_total = bcsub($price_goods + $price_express,$total_discount,2);
+            $order_insert['price_total'] = $price_total;
+            $order_insert['price_goods'] = $price_goods ;
+            $order_insert['original_total'] = $original_total ;
+            $order_insert['price_express'] = $price_express ;
+            $order_insert['total_discount'] = $total_discount ;
+            $order_insert['redu_money'] = $redu_money ;
+            $order_info = GoodsOrder::create($order_insert);// 生成订单
+
+            array_walk($order_item,function (&$v,$k)use($order_info,$total_discount){
+                $v['order_id'] = $order_info->id;
+                if($total_discount > 0){
+                    $v['pay_price'] = $v['sell_price']*$v['num'] - bcmul($total_discount , bcdiv($v['sell_price']*$v['num'],$order_info->price_goods,2),2) ;
+                }
+            });
+            (new GoodsOrderItem())->saveAll($order_item);// 生成订单商品详情
+            ShoppingTrolley::where('id','in',$ids)->delete();// 删除购物车
+            $ret_data['order_id'] =  $order_info->id;
+            Db::commit();
+        }catch (\Exception $e){
+            $this->ret_msg = $e->getMessage();
+            $this->is_commit = false;
+            Db::rollback();
+        }
+        $this->transReturn($ret_data);
+    }
+
+    /**
+     * @title 计算商品运费(一个商品id)
+     * @desc  计算商品运费(一个商品id)
+     * @author qc
+     * @url /api/Order/getGoodsFreight
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:goods_id type:int require:1  default:0 desc:商品id
+     * @param  name:num type:int require:1  default:0 desc:商品数量
+     * @param  name:add_id type:int require:1  default:0 desc:收货地址id
+     * @return name:freight type:float require:0 default:0 desc运费金额
+     */
+    public function getGoodsFreight()
+    {
+        $goods_id = input('get.goods_id');
+        $num = input('get.num');
+        $add_id = input('get.add_id');
+        $goods_info = StoreGoods::where('id',$goods_id)->find()->toArray();
+        $add_info = DeliveryAddress::where('id',$add_id)->find()->toArray();
+        $freight_data = ExpressService::getGoodsExpressPrice($goods_info,$add_info,$num);
+        if($freight_data['code'] != 200 ) $this->error($freight_data['msg']);
+        $this->success('ok',['freight'=>$freight_data['freight']]);
+    }
+
+    /**
+     * @title 计算购物车商品运费
+     * @desc  计算购物车商品运费
+     * @author qc
+     * @url /api/Order/getTrolleyFreight
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:ids type:int require:1  default:0 desc:购物车商品id串
+     * @param  name:add_id type:int require:1  default:0 desc:收货地址id
+     * @return name:freight type:float require:0 default:0 desc运费金额
+     */
+    public function getTrolleyFreight()
+    {
+        $trolley_ids = input('get.ids');
+        $add_id = input('get.add_id');
+        $goods_list = ShoppingTrolley::where('id','in',$trolley_ids)
+            ->field('goods_id,sum(num) as total_num')
+            ->group('goods_id')
+            ->select()->toArray();
+        $total_price = 0;
+        $add_info = DeliveryAddress::where('id',$add_id)->find()->toArray();
+        foreach ($goods_list as $v){
+            $goods_info = StoreGoods::field('name,freight_type,freight_id,postage')->where('id',$v['goods_id'])->find()->toArray();
+            $freight_data = ExpressService::getGoodsExpressPrice($goods_info,$add_info,$v['total_num']);
+            if($freight_data['code'] != 200){
+                $this->error($goods_info['name'].$freight_data['msg']);
+                break;
+            }
+            $total_price += $freight_data['freight'];
+        }
+        $this->success('ok',['freight'=>$total_price]);
+    }
+
+
+    /**
+     * @title 获取订单列表
+     * @desc 订单优惠:int_cash + coupon_cash
+     * @author qc
+     * @method GET
+     * @url /api/Order/getOrderList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数
+     * @param  name:status type:int default:-1  desc:状态
+     * @param  name:apply_refund type:int default:-1  desc:申请退款状态(-1全部,0未申请||已取消,1已申请)
+     * @return name:id type:int default:--  desc:订单id
+     * @return name:order_no type:string default:--  desc:订单号
+     * @return name:price_total type:float default:--  desc:待支付金额(所以优惠完价格+运费)
+     * @return name:price_goods type:float default:--  desc:商品金额(用售价计算)
+     * @return name:price_express type:float default:--  desc:运费金额
+     * @return name:original_total type:float default:--  desc:总原价(下划线)
+     * @return name:pay_state type:int default:--  desc:支付状态(0未支付1已支付)
+     * @return name:pay_type type:int default:--  desc:支付方式(1微信2余额3支付宝)
+     * @return name:pay_no type:string default:--  desc:支付号
+     * @return name:pay_at type:string default:--  desc:支付时间
+     * @return name:cancel_state type:int default:--  desc:取消状态(0未取消1已取消)
+     * @return name:cancel_at type:string default:--  desc:取消时间
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:refund_state type:int default:--  desc:退款状态(0未申请 1待审核,2审核通过,3审核拒绝)
+     * @return name:express_state type:int default:--  desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_title type:string default:--  desc:发货快递公司名称
+     * @return name:express_send_no type:string default:--  desc:物流单号
+     * @return name:express_send_at type:string default:--  desc:发货时间
+     * @return name:status type:int default:--  desc:订单状态(0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,8已退款,9取消)
+     * @return name:create_at type:string default:--  desc:下单时间
+     * @return name:integral type:string default:--  desc:使用积分数量
+     * @return name:int_cash type:float default:--  desc:使用积分抵扣金额
+     * @return name:cl_ids type:string default:--  desc:使用优惠券id串
+     * @return name:coupon_cash type:string default:--  desc:使用优惠券抵扣金额
+     * @return name:blance type:string default:--  desc:使用余额支付金额
+     * @return name:redu_money type:float default:--  desc:订单满减金额
+     * @return name:remark type:string default:--  desc:订单备注
+     * @return name:goods_num type:int default:--  desc:订单商品总数量
+     * @return name:pro_name type:string default:--  desc:省名称(收货地址)
+     * @return name:city_name type:string default:--  desc:市名称(收货地址)
+     * @return name:county_name type:string default:--  desc:县区名称(收货地址)
+     * @return name:street_name type:string default:--  desc:街道名称(收货地址)
+     * @return name:add_detail type:string default:--  desc:详细地址(收货地址)
+     * @return name:user_name type:string default:--  desc:收货人
+     * @return name:phone type:string default:--  desc:收货人联系电话
+     * @return name:act_type type:int default:--  desc:活动类型0无1秒杀2拼团
+     * @return name:act_id type:int default:--  desc:活动id
+     * @return name:share_user type:int default:--  desc:分享人id
+     * @return name:order_item type:array default:--  desc:订单商品列表
+     * @return name:order_item.name type:float default:--  desc:商品名
+     * @return name:order_item.cover type:float default:--  desc:商品图
+     * @return name:order_item.sell_price type:float default:--  desc:购买价格
+     * @return name:order_item.goods_spec type:float default:--  desc:规格
+     * @return name:order_item.num type:int default:--  desc:数量
+     * @return name:order_bill type:array default:--  desc:订单开票数据(为空则未申请)
+     * @return name:order_bill.header type:string require:1  default:0 desc:抬头
+     * @return name:order_bill.type type:string require:1  default:0 desc:类型(string)
+     * @return name:order_bill.email type:string require:1  default:0 desc:邮箱(string)
+     * @return name:order_bill.bank type:string require:1  default:0 desc:开户行(string)
+     * @return name:order_bill.card_no type:string require:1  default:0 desc:账号(string)
+     * @return name:order_bill.phone type:string require:1  default:0 desc:电话(string)
+     * @return name:order_bill.status type:int require:1  default:0 desc:0待开票1已开票
+     * @return name:order_refund type:array require:1  default:0 desc:退款申请信息
+     * @return name:order_refund.status type:int default:0 desc:审核状态(0待审核1同意退款2审核拒绝3通过切退款4退款异常5取消申请)
+     * @return name:order_refund.is_deleted type:int default:0 desc:是否已删除(0否1是)
+     */
+    public function getOrderList()
+    {
+        $status = input('get.status',-1);
+        $refund_state = input('get.apply_refund',-1);
+        $where = [];
+        $where[] = ['user_id','=',$this->user_id];
+        if($status > -1) $where[] = ['status','=',$status];
+        if($refund_state == 0) $where[] = ['refund_state','=',$refund_state];
+        if($refund_state == 1) $where[] = ['refund_state','in','1,2,3,4'];
+        $list = GoodsOrder::with(['orderItem','orderBill','orderRefund'])->where($where)->order('id desc ')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        $this->success('',['list'=>$list]);
+    }
+
+
+    /**
+     * @title 获取订单详情
+     * @desc 获取订单详情
+     * @author qc
+     * @method GET
+     * @url /api/Order/getOrderDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param name:order_id type:int default:--  desc:订单id
+     * @return name:id type:int default:--  desc:订单id
+     * @return name:order_no type:string default:--  desc:订单号
+     * @return name:price_total type:float default:--  desc:待支付金额(所以优惠完价格+运费)
+     * @return name:price_goods type:float default:--  desc:商品金额
+     * @return name:price_express type:float default:--  desc:运费金额
+     * @return name:original_total type:float default:--  desc:总原价(下划线)
+     * @return name:original_total type:float default:--  desc:总原价(下划线)
+     * @return name:pay_state type:int default:--  desc:支付状态(0未支付1已支付)
+     * @return name:pay_type type:int default:--  desc:支付方式(1微信2余额3支付宝)
+     * @return name:pay_no type:string default:--  desc:支付号
+     * @return name:pay_at type:string default:--  desc:支付时间
+     * @return name:cancel_state type:int default:--  desc:取消状态(0未取消1已取消)
+     * @return name:cancel_at type:string default:--  desc:取消时间
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:cancel_desc type:string default:--  desc:取消原因
+     * @return name:refund_state type:int default:--  desc:退款状态(0未申请1待审核,2审核拒绝,3审核通过)
+     * @return name:express_state type:int default:--  desc:发货状态(0未发货,1已发货,2已签收)
+     * @return name:express_company_title type:string default:--  desc:发货快递公司名称
+     * @return name:express_send_no type:string default:--  desc:物流单号
+     * @return name:express_send_at type:string default:--  desc:发货时间
+     * @return name:status type:int default:--  desc:订单状态(0待支付,1已支付(待发货),2已发货(待收货),3已收货(待评论)4已完成,8已退款,9取消)
+     * @return name:create_at type:string default:--  desc:下单时间
+     * @return name:integral type:string default:--  desc:使用积分数量
+     * @return name:cl_ids type:string default:--  desc:使用优惠券id串
+     * @return name:coupon_cash type:string default:--  desc:使用优惠券抵扣金额
+     * @return name:blance type:string default:--  desc:使用余额支付金额(余额抵扣)
+     * @return name:redu_money type:float default:--  desc:订单满减金额
+     * @return name:remark type:string default:--  desc:订单备注
+     * @return name:goods_num type:int default:--  desc:订单商品总数量
+     * @return name:pro_name type:string default:--  desc:省名称(收货地址)
+     * @return name:city_name type:string default:--  desc:市名称(收货地址)
+     * @return name:county_name type:string default:--  desc:县区名称(收货地址)
+     * @return name:street_name type:string default:--  desc:街道名称(收货地址)
+     * @return name:add_detail type:string default:--  desc:详细地址(收货地址)
+     * @return name:user_name type:string default:--  desc:收货人
+     * @return name:phone type:string default:--  desc:收货人联系电话
+     * @return name:act_type type:int default:--  desc:活动类型0无1秒杀2拼团
+     * @return name:act_id type:int default:--  desc:活动id
+     * @return name:share_user type:int default:--  desc:分享人id
+     * @return name:order_item type:array default:--  desc:订单商品列表(按商品id分组)
+     * @return name:order_item.name type:float default:--  desc:商品名
+     * @return name:order_item.cover type:float default:--  desc:商品图
+     * @return name:order_item.sell_price type:float default:--  desc:购买价格
+     * @return name:order_item.goods_spec type:float default:--  desc:规格
+     * @return name:order_item.num type:int default:--  desc:数量
+     */
+    public function getOrderDetail()
+    {
+        $order_id = input('get.order_id');
+        $detail = GoodsOrder::where('id',$order_id)->find()->toArray();
+        $detail['order_item']  = (new GoodsOrderItem())->getOrderItem($order_id);
+        $this->success('',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 取消订单
+     * @desc  取消订单
+     * @author  qc
+     * @url /api/Order/cancelOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function cancelOrder()
+    {
+        $order_id = input('post.order_id');
+        Db::startTrans();
+        try {
+            $detail = GoodsOrder::with('orderItem')->where('id',$order_id)->find()->toArray();
+            if($detail['status'] != 0) $this->exception('订单状态有误');
+            // 取消订单状态
+            GoodsOrder::update(['status'=>9],['id'=>$order_id]);
+            // 优惠券退回
+            if($detail['cl_ids']) UserCouponList::where(['id','in',$detail['cl_ids']])->update(['status'=>0]);
+            // 积分退回
+            if($detail['integral'] > 0) UserWallet::userIntegralChange($detail['user_id'],$detail['integral'],'订单取消退回',2,1,$detail['id']);
+            // 余额退回
+            if($detail['blance'] > 0) UserWallet::userMoneyChange($detail['user_id'],$detail['blance'],'订单取消退回',2, 1,$detail['id']);
+            // 订单处理
+            foreach ($detail['order_item'] as $item_info) {
+                //  更改订单详情状态
+                GoodsOrderItem::update(['status'=>9],['id'=>$item_info['id']]);
+                // 商品规格库存返回
+                StoreGoodsItem::where('id',$item_info['spec_id'])->setInc('stock',$item_info['num']);
+                // 商品总库存增加
+                StoreGoods::where('id',$item_info['goods_id'])->setInc('stock',$item_info['num']);
+            }
+            if($detail['act_type'] == 2 && $detail['leader_id']) {
+                GroupLeader::where(['id'=>$detail['leader_id']])->update(['status'=>0]);
+            }
+           /* switch ($detail['act_type']){
+                case 1:
+                   // $redis =  new Redis();
+                   // $redis_prefix = 'SECKILL_'.$detail['act_id'].'_';
+                    foreach ($detail['order_item'] as $item_info) {
+                        //  更改订单详情状态
+                        GoodsOrderItem::update(['status'=>9],['id'=>$item_info['id']]);
+                        // 商品规格库存返回
+                        $item = SeckillGoodsItem::where(['act_id'=>$detail['act_id'],'goods_id'=>$item_info['goods_id'],'spec_id'=>$item_info['spec_id']])->find()->toArray();
+                        SeckillGoodsItem::where(['id'=>$item['id']])->setInc('stock',$item_info['num']);
+                       // $redis->inc($redis_prefix.$item['id'].'_stock',$item_info['num']);//增加redis
+                    }
+                    break;
+                case 2:
+                   // $redis =  new Redis();
+                    //$redis_prefix = 'GROUP_'.$detail['act_id'].'_';
+                    //拼团锁定的退款
+                    if($detail['leader_id']){
+                        GroupLeader::where(['id'=>$detail['leader_id']])->update(['status'=>0]);
+                       // $redis->set(  $redis_prefix.$detail['leader_id'],0);
+                    }
+                    foreach ($detail['order_item'] as $item_info) {
+                        //  更改订单详情状态
+                        GoodsOrderItem::update(['status'=>9],['id'=>$item_info['id']]);
+                        // 商品规格库存返回
+                        $item = GroupGoodsItem::where(['act_id'=>$detail['act_id'],'goods_id'=>$item_info['goods_id'],'spec_id'=>$item_info['spec_id']])->find()->toArray();
+                        GroupGoodsItem::where(['id'=>$item['id']])->setInc('stock',$item_info['num']);
+                       // $redis->inc($redis_prefix.$item['id'].'_stock',$item_info['num']);//增加redis
+                    }
+                    break;
+            }*/
+            Db::commit();
+        }catch (\Exception $e){
+            $this->ret_msg = $e->getMessage();
+            $this->is_commit = false;
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('取消成功') : $this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 删除订单
+     * @desc  删除订单
+     * @author  qc
+     * @url /api/Order/deleteOrder
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function deleteOrder()
+    {
+        $order_id = input('post.order_id');
+        $detail = GoodsOrder::with('orderItem')->where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 0) $this->error('请先取消订单');
+        GoodsOrder::update(['is_deleted'=>1],['id'=>$order_id]);
+        $this->success('删除成功');
+    }
+
+    /**
+     * @title 更换订单收货地址
+     * @desc  更换订单收货地址(仅待支付订单可以修改地址)
+     * @author  qc
+     * @url /api/Order/changeOrderDelivery
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:add_id type:int require:1  default:0 desc:收货地址id
+     */
+    public function changeOrderDelivery()
+    {
+        $order_id = input('post.order_id');
+        $add_id = input('post.add_id');
+        $detail = GoodsOrder::where('id',$order_id)->find()->toArray();
+        if($detail['status'] != 0) $this->error('操作错误');
+        $add_info = DeliveryAddress::where('id',$add_id)->find()->toArray();
+        $order_update =[
+            'pro_name' => $add_info['pro_name'],
+            'city_name' => $add_info['city_name'],
+            'county_name' => $add_info['county_name'],
+            'street_name' => $add_info['street_name'],
+            'add_detail' => $add_info['detail'],
+            'user_name' => $add_info['name'],
+            'phone' => $add_info['phone'],
+        ];
+        GoodsOrder::update($order_update,['id'=>$order_id]);
+        $this->success('修改成功');
+
+    }
+
+    /**
+     * @title 确认收货
+     * @desc  确认收货
+     * @author  qc
+     * @url /api/Order/confirmReceipt
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     */
+    public function confirmReceipt()
+    {
+        $order_id = input('post.order_id');
+        $detail = GoodsOrder::with('orderItem')->where('id',$order_id)->find()->toArray();
+        if($detail['status'] == 0) $this->error('订单未支付');
+        if($detail['status'] == 1) $this->error('订单未发货');
+        if($detail['status'] == 3) $this->error('订单已收货');
+        GoodsOrder::update(['status'=>3],['id'=>$order_id]);
+        GoodsOrderItem::update(['status'=>3],['order_id'=>$order_id]);
+        UserMessage::create(['user_id'=>$this->user_id,'type_id'=>3,'relation_id'=>$order_id,'content'=>'订单收货成功']);
+        $this->success('已确认收货');
+    }
+
+    /**
+     * @title 订单评价
+     * @desc  订单评价
+     * @author  qc
+     * @url /api/Order/orderComment
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:item_id type:int require:1  default:0 desc:订单item表id
+     * @param  name:content type:string require:1  default:0 desc:评论内容
+     * @param  name:images type:string default:0 desc:图片
+     * @param  name:video type:string default:0 desc:视频
+     * @param  name:goods_core type:int default:0 desc:商品评分
+     * @param  name:wl_core type:int default:0 desc:物流评分
+     * @param  name:serve_core type:int default:0 desc:服务评分
+     */
+    public function orderComment()
+    {
+        $item_id = input('post.item_id','');
+        $content = input('post.content','');
+        $images = input('post.images','');
+        $video = input('post.video','');
+        $goods_core = input('post.goods_core','');
+        $wl_core = input('post.wl_core','');
+        $serve_core = input('post.serve_core','');
+        $item = GoodsOrderItem::get($item_id);
+        if(!$item) $this->error('订单不存在');
+        $order_info = GoodsOrder::where('id',$item->order_id)->find();
+        if($order_info->status < 3) $this->error('请先确认收货');
+        $data = [
+            'user_id' => $this->user_id,
+            'order_id' =>$item->order_id,
+            'goods_id' =>$item->goods_id,
+            'spec_id' =>$item->spec_id,
+            'content' =>$content,
+            'images' =>$images,
+            'video' =>$video,
+            'goods_core' =>$goods_core,
+            'wl_core' =>$wl_core,
+            'serve_core' =>$serve_core,
+        ];
+        OrderComment::create($data);
+        $this->success('评论成功');
+    }
+
+    /**
+     * @title 获取退款理由
+     * @desc  获取退款理由
+     * @author  qc
+     * @url /api/Order/getRefundCase
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:apply_case type:string default:0 desc:退款原因
+     * @param  name:images type:string default:0 desc:图片
+     */
+    public function getRefundCase()
+    {
+        $list= Db::name('order_refund_case')->order('sort desc ,id desc')->select();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+    /**
+     * @title 订单申请退款(重新退款||退款编辑)
+     * @desc  订单申请退款
+     * @author  qc
+     * @url /api/Order/orderRefund
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:apply_case type:string default:0 desc:退款原因
+     * @param  name:images type:string default:0 desc:图片
+     */
+    public function orderRefund()
+    {
+        $order_id = input('post.order_id');
+        $apply_case = input('post.apply_case');
+        $images = input('post.images');
+        $order_info = GoodsOrder::where('id',$order_id)->find()->toArray();
+        if($order_info['status'] == 0) $this->error('订单未支付');
+        if($order_info['refund_state'] == 1) $this->error('订单已申请,等待审核');
+        if($order_info['refund_state'] == 2) $this->error('已通过审核');
+        $refund_info = [
+            'user_id' => $this->user_id ,
+            'order_id' => $order_id ,
+            'num' => $order_info['goods_num'],
+            'apply_case' => $apply_case,
+            'images' => $images,
+            'is_deleted'=> 0,
+            'refund_type'=> $order_info['status'] == 1 ? :2,
+            'create_at'=> date('Y-m-d H:i:s'),
+            'refund_no'=> 'R'.$order_info['order_no'],
+        ];
+        Data::save('StoreOrderRefund',$refund_info,'order_id',['order_id'=>$order_id]);
+        GoodsOrder::where(['id'=>$order_id])->update(['refund_state'=>1]);
+        $this->success('申请成功等待审核');
+    }
+
+    /**
+     * @title 取消退款申请
+     * @desc  取消退款申请
+     * @author qc
+     * @url /api/Order/cancelApply
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int require:1  default:0 desc:退款记录id
+     */
+    public function cancelApply()
+    {
+        $id = input('post.id');
+        $refund_info = StoreOrderRefund::where('id',$id)->find();
+        if($refund_info['status'] != 0) $this->error('该记录已处理!');
+        StoreOrderRefund::where('id',$id)->update(['status'=>5]);
+        GoodsOrder::where('id',$refund_info['order_id'])->update(['refund_state'=>0]);
+        $this->success('取消成功!');
+    }
+
+    /**
+     * @title 订单退款详情
+     * @desc  订单退款详情
+     * @author  qc
+     * @url /api/Order/getRefundInfo
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @return name:apply_case type:string default:0 desc:退款原因
+     * @return name:images type:string default:0 desc:图片
+     * @return name:create_at type:string default:0 desc:申请时间
+     * @return name:status type:int default:0 desc:0待审核1同意退款2审核拒绝(失败)3通过切退款成功4退款异常5取消申请
+     * @return name:refund_type type:int default:0 desc:1退款2退款退货
+     * @return name:audit_desc type:string default:0 desc:审核描述
+     * @return name:refund_money type:float default:0 desc:审核退款金额
+     * @return name:refund_time type:float default:0 desc:退款到账时间
+     * @return name:audit_at type:float default:0 desc:审核时间
+     * @return name:refund_no type:float default:0 desc:退款编号
+     * @return name:express_info type:array default:0 desc:退货物流
+     * @return name:express_info.express_address type:string default:0 desc:0 desc:退货地址
+     * @return name:express_info.express_user type:string default:0 desc:0 desc:收件人
+     * @return name:express_info.express_tel type:string default:0 desc:0 desc:电话
+     * @return name:express_info.express_name type:string default:0 desc:0 desc:物流公司名称
+     * @return name:express_info.express_no type:string default:0 desc:快递号
+     * @return name:express_info.express_time type:string default:0 desc:时间
+     */
+    public function getRefundInfo()
+    {
+        $order_id = input('get.order_id');
+        $refund_info = StoreOrderRefund::where('order_id',$order_id)
+            ->field('id,apply_case,images,status,audit_desc,create_at,express_info,refund_type,refund_no,audit_at,refund_time')
+            ->find()->toArray();
+        if($refund_info['express_info'])$refund_info['express_info']= json_decode($refund_info['express_info'],true);
+        $this->success('ok',['detail'=>$refund_info]);
+    }
+
+    /**
+     * @title 完善退款物流
+     * @desc  完善退款物流
+     * @author  qc
+     * @url /api/Order/refundExpress
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int require:1  default:0 desc:退款记录id
+     * @param  name:express_address type:string default:0 desc:0 desc:退货地址
+     * @param  name:express_user type:string default:0 desc:0 desc:收件人
+     * @param  name:express_tel type:string default:0 desc:0 desc:电话
+     * @param  name:express_name type:string default:0 desc:0 desc:物流公司名称(退货的物流公司是用户自己填写的,,,想用哪个用哪个)
+     * @param  name:express_no type:string default:0 desc:快递号
+     */
+    public function refundExpress()
+    {
+        $id = input('post.id');
+        $express_address = input('post.express_address');
+        $express_user = input('post.express_user');
+        $express_tel= input('post.express_tel');
+        $express_name= input('post.express_name');
+        $express_no = input('post.express_no');
+        $exp_info = [
+            'express_address'=>$express_address,
+            'express_user'=>$express_user,
+            'express_tel'=>$express_tel,
+            'express_name'=>$express_name,
+            'express_no'=>$express_no,
+            'express_time'=>date("Y-m-d H:i:s"),
+        ];
+        StoreOrderRefund::where('id',$id)->update(['express_info'=>json_encode($exp_info)]);
+        $this->success('物流信息完善成功');
+    }
+
+    /**
+     * @title 申请(修改)订单发票
+     * @desc  申请(修改)订单发票
+     * @author qc
+     * @url /api/Order/applyOrderBill
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @param  name:header type:string require:1  default:0 desc:抬头
+     * @param  name:type type:string require:1  default:0 desc:类型(string)
+     * @param  name:email type:string require:1  default:0 desc:邮箱(string)
+     * @param  name:bank type:string require:1  default:0 desc:开户行(string)
+     * @param  name:card_no type:string require:1  default:0 desc:账号(string)
+     * @param  name:phone type:string require:1  default:0 desc:电话(string)
+     */
+    public function applyOrderBill()
+    {
+        $order_id = input('order_id');
+        $bill_status = OrderBill::where(['order_id'=>$order_id])->value('status');
+        if($bill_status) $this->error('已开票');
+        $header = input('post.header');
+        $type = input('post.type');
+        $email = input('post.email');
+        $bank = input('post.bank');
+        $card_no = input('post.card_no');
+        $phone = input('post.phone');
+        Data::save('OrderBill',$_POST,'order_id',['order_id'=>$order_id]);
+        $this->success('申请成功');
+    }
+
+    /**
+     * @title 获取订单发票详情
+     * @desc  获取订单发票详情
+     * @author qc
+     * @url /api/Order/getBillInfo
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:order_id type:int require:1  default:0 desc:订单id
+     * @return name:header type:string require:1  default:0 desc:抬头
+     * @return name:type type:string require:1  default:0 desc:类型(string)
+     * @return name:email type:string require:1  default:0 desc:邮箱(string)
+     * @return name:bank type:string require:1  default:0 desc:开户行(string)
+     * @return name:card_no type:string require:1  default:0 desc:账号(string)
+     * @return name:phone type:string require:1  default:0 desc:电话(string)
+     */
+    public function getBillInfo()
+    {
+        $detail = OrderBill::where('order_id',input('order_id'))->find();
+        $this->success('ok',['detail'=>$detail ?$detail->toArray() :'']);
+    }
+
+
+
+}

+ 50 - 0
application/api/controller/Qc.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\api\controller;
+use app\api\controller\WeChart;
+use app\common\model\ChinaArea;
+use app\common\model\GoodsOrder;
+use app\common\model\OrderBill;
+use app\common\model\ReductionActivity;
+use app\common\model\StoreGoods;
+use app\common\model\User;
+use app\common\model\UserWallet;
+use app\common\service\Activity;
+use app\order\controller\StoreOrder;
+use EasyWeChat\MiniProgram\Application;
+use library\tools\Data;
+use think\Exception;
+use think\Session;
+use think\cache\driver\Redis;
+use EasyWeChat\Factory;
+use Firebase\JWT\JWT;
+use think\Db;
+use AlibabaCloud\Client\AlibabaCloud;
+use AlibabaCloud\Client\Exception\ClientException;
+use AlibabaCloud\Client\Exception\ServerException;
+use function AlibabaCloud\Client\value;
+use function Stringy\create;
+
+class Qc extends Base {
+
+    public function index()
+    {
+       $red = ReductionActivity::getReduction(750);
+       $re2 = ReductionActivity::getReduction(95);
+       var_dump($red,$re2);
+    }
+
+
+    public function index_match()
+    {
+        $password = "123456879_/";
+        //密码必须包含大小写字母/数字/符号任意两者组合
+        $regStr = "/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[\(\)])+$)([^(0-9a-zA-Z)]|[\(\)]|[a-z]|[A-Z]|[0-9]){6,16}$/";
+        var_dump(preg_match($regStr, $password));
+
+    }
+
+
+
+
+}

+ 235 - 0
application/api/controller/Sign.php

@@ -0,0 +1,235 @@
+<?php
+namespace app\api\controller;
+use app\common\model\UserSignCard;
+use app\common\model\UserWallet;
+use think\Db;
+use app\common\model\UserSign;
+/**
+ * @title 会员签到
+ * @controller Sign
+ * @group base
+ */
+class Sign extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 验证会员当天是否签到
+     * @desc  验证会员当天是否签到
+     * @author qc
+     * @url /api/Sign/checkSign
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return  name:is_sign type:int  default:0  desc:是否签到0未签到,1已签到
+     */
+    public function checkSign()
+    {
+        $year = date('Y');
+        $month = date('m');
+        $day = date('d');
+        $ck_sign = UserSign::where(['user_id'=>$this->user_id,'year'=>$year,'month'=>$month,'day'=>$day])->count();
+        $this->success('ok',['is_sign'=>$ck_sign]);
+    }
+
+    /**
+     * @title 获取会员连续签到天数
+     * @desc  获取会员连续签到天数
+     * @author qc
+     * @url /api/Sign/getContinuousSign
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:is_sign type:int  default:-- desc:当天是否签到(0签到,1已签到)
+     * @return name:sign_num type:int  default:-- desc:连续签到天数
+     * @return name:sign_card type:int  default:-- desc:补签卡数量
+     */
+    public function getContinuousSign()
+    {
+        $today_sign =  UserSign::where(['user_id'=>$this->user_id,'day_time'=>date('Y-m-d')])->find();
+        $is_sign = !empty($today_sign) ? 1:0;
+        $sign_num = 0;
+        $week_sign = UserSign::where('user_id','=',$this->user_id)
+            ->where('create_at','>= time',date('Y-m-d 00:00:00',strtotime('-6 days')))
+            ->where('status','=',0)
+            ->order('create_at desc')
+            ->select()->toArray();
+        $sign_date =  array_column($week_sign,'day_time');
+        for($i=0;$i<=6;$i++) {
+            if(in_array(date('Y-m-d',strtotime("-$i days")),$sign_date)){
+                $sign_num++;
+            }else if($i>0){
+                break;
+            }
+        }
+        $sign_card = UserSignCard::where(['user_id'=>$this->user_id,'status'=>0])->count();
+        $this->success('ok',['sign_num'=>$sign_num,'is_sign'=>$is_sign,'sign_card'=>$sign_card]);
+    }
+
+    /**
+     * @title 会员签到
+     * @desc 会员签到
+     * @author qc
+     * @url /api/Sign/userSign
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @return name:integral type:int  default:--  desc:签到获得积分数
+     * @return name:next_integral type:int  default:--  desc:明日签到积分
+     * @return name:sign_num type:int  default:--  desc:连续签到天数
+     */
+    public function userSign()
+    {
+        $year = date('Y');
+        $month = date('m');
+        $day = date('d');
+        $ck_sign = UserSign::where(['user_id'=>$this->user_id,'year'=>$year,'month'=>$month,'day'=>$day])->count();
+        if($ck_sign) $this->error('已签到');
+        $sign_data=[
+            'user_id' =>$this->user_id,
+            'year' =>$year,
+            'month' =>$month,
+            'day' =>$day,
+            'day_time'=>date('Y-m-d'),
+            'create_at' => date('Y-m-d H:i:s'),
+            'desc' => '每日签到',
+        ];
+        UserSign::create($sign_data);
+
+        $sign_num = 0;
+        // 最近七天签到情况
+        $week_sign = UserSign::where('user_id','=',$this->user_id)
+            ->where('create_at','>= time',date('Y-m-d 00:00:00',strtotime('-6 days')))
+            ->where('status','=',0)
+            ->order('create_at desc')
+            ->select()->toArray();
+        $sign_date =  array_column($week_sign,'day_time');
+        for($i=0;$i<=6;$i++) {
+            if(in_array(date('Y-m-d',strtotime("-$i days")),$sign_date)){
+                $sign_num++;
+            }else if($i>0){
+                break;
+            }
+        }
+        $integral = in_array($sign_num,[2,3]) ? $sign_num:1;
+        UserWallet::userIntegralChange($this->user_id,$integral,'签到奖励',6, 1);
+        UserWallet::userExpChange($this->user_id,$integral,'签到奖励');
+        $next_integral = 1;
+        if(in_array($sign_num,[1,2]))$next_integral += $sign_num;
+        $this->success('签到成功',['integral'=>$integral,'sign_num'=>$sign_num,'next_integral'=>$next_integral]);
+    }
+
+    /**
+     * @title 会员领取签到卡
+     * @desc 会员领取签到卡
+     * @author qc
+     * @url /api/Sign/getSignCard
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     */
+    public function getSignCard()
+    {
+        $sign_num = 0;
+        // 最近七天签到情况
+        $week_sign = UserSign::where('user_id','=',$this->user_id)
+            ->where('create_at','>= time',date('Y-m-d 00:00:00',strtotime('-6 days')))
+            ->where('status','=',0)
+            ->order('create_at desc')
+            ->count();
+        $sign_date =  array_column($week_sign,'day_time');
+        for($i=0;$i<=6;$i++) {
+            if(in_array(date('Y-m-d',strtotime("-$i days")),$sign_date)){
+                $sign_num++;
+            }else if($i>0){
+                break;
+            }
+        }
+        if($sign_num != 7) $this->error('连续签到天数不足7天');
+        UserSign::where('user_id','=',$this->user_id)
+            ->where('create_at','>= time',date('Y-m-d 00:00:00',strtotime('-6 days')))
+            ->where('status','=',0)
+            ->update(['status'=>1]);
+        UserSignCard::create([ 'user_id' => $this->user_id]);
+        $this->success('领取成功');
+    }
+
+
+    /**
+     * @title 会员补签
+     * @desc 会员补签
+     * @author qc
+     * @url /api/Sign/retroactive
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:date_time type:int  default:--  desc:补签日期(2022-04-07)
+     * @return name:integral type:int  default:--  desc:签到获得积分数
+     * @return name:next_integral type:int  default:--  desc:明日签到积分
+     * @return name:sign_num type:int  default:--  desc:连续签到天数
+     */
+    public function retroactive()
+    {
+        $date_time = input('post.date_time',date('Y-m-d'));
+        $year = date('Y',strtotime($date_time));
+        $month = date('m',strtotime($date_time));
+        $day = date('d',strtotime($date_time));
+        $ck_sign = UserSign::where(['user_id'=>$this->user_id,'year'=>$year,'month'=>$month,'day'=>$day])->count();
+        if($ck_sign) $this->error('已签到');
+        $user_card = UserSignCard::where(['user_id'=>$this->user_id,'status'=>0])->min('id');
+        if(!$user_card) $this->error('补签卡不足');
+        $sign_data=[
+            'user_id' =>$this->user_id,
+            'year' =>$year,
+            'month' =>$month,
+            'day' =>$day,
+            'day_time'=>$date_time,
+            'create_at' => $date_time . date('H:i:s'),
+            'desc' => '每日签到(补签)',
+        ];
+        UserSign::create($sign_data);
+
+        $sign_num = 0;
+        // 最近七天签到情况
+        $week_sign = UserSign::where('user_id','=',$this->user_id)
+            ->where('create_at','>= time',date('Y-m-d 00:00:00',strtotime('-6 days')))
+            ->where('status','=',0)
+            ->order('create_at desc')
+            ->select()->toArray();
+        $sign_date =  array_column($week_sign,'day_time');
+        for($i=0;$i<=6;$i++) {
+            if(in_array(date('Y-m-d',strtotime("-$i days")),$sign_date)){
+                $sign_num++;
+            }else if($i>0){
+                break;
+            }
+        }
+        $integral = in_array($sign_num,[2,3]) ? $sign_num:1;
+        $next_integral = 1;
+        if(in_array($sign_num,[1,2]))$next_integral += $sign_num;
+        $this->success('补签成功',['integral'=>$integral,'sign_num'=>$sign_num,'next_integral'=>$next_integral]);
+    }
+
+
+    /**
+     * @title 会员签到列表
+     * @desc  会员签到列表
+     * @author  qc
+     * @url /api/Sign/getSignList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:desc type:string default:-- desc:描述
+     */
+    public function getSignList()
+    {
+        $list = UserSign::field('id,create_at,desc')
+            ->where('user_id','=',$this->user_id)
+            ->order('id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select();
+        $this->success('ok',['list'=>$list ? $list->toAray() :[]]);
+    }
+
+}

+ 83 - 0
application/api/controller/Task.php

@@ -0,0 +1,83 @@
+<?php
+namespace app\api\controller;
+use app\common\model\PartnerLevel;
+use app\common\model\User;
+use app\common\model\UserCouponList;
+use app\common\model\UserExpLog;
+use app\common\model\UserGrowthLog;
+use app\common\model\UserIntegralLog;
+use app\common\model\UserLevel;
+use app\common\model\UserWallet;
+use app\common\service\UserIdentity;
+
+
+/**
+ * @title 定时任务
+ * Class Task
+ * @controller Task
+ * @group base
+ */
+class Task extends Base
+{
+    // 会员等级
+    public function checkUserLevel()
+    {
+        $user_level     = UserLevel::column('id,name,growth','id');
+        $partner_level  = PartnerLevel::column('id,name,growth','id');
+        $last_year = date('Y-m-d H:i:s',strtotime('-1 year'));
+        $user_list = User::field('id,level_id,partner_lev,is_partner')
+            ->with('wallet')
+            ->where('create_at','> time',$last_year)
+            ->select()->toArray();
+        foreach ($user_list as $v)
+        {
+            // 一年内获得的经验值
+            $exp  = UserExpLog::where('create_at','> time',$last_year)
+                ->where('user_id','=',$v['id'])
+                ->where('is_deleted','=',0)
+                ->where('exp','>',0)
+                ->sum('exp');
+            // 经验过期
+            if($exp < $v['wallet']['level_exp']) {
+                UserWallet::userExpChange($v['id'],$v['wallet']['level_exp']-$exp,'经验过期',-1);
+                $v['wallet']['level_exp'] = $exp;
+                // 更新会员等级
+                UserIdentity::userLevel($v,$user_level,$v['id']);
+            }
+
+            //近一年获得的积分
+            $integral = UserIntegralLog::where('create_at','> time',$last_year)
+                ->where('user_id','=',$v['id'])
+                ->where('type','in',[5,6,7])
+                ->where('is_deleted','=',0)
+                ->where('integral','>',0)
+                ->sum('integral');
+            // 积分过期
+            if($integral < $v['wallet']['integral']) UserWallet::userIntegralChange($v['id'],$v['wallet']['integral']-$integral,'积分过期',8,-1);
+
+            // 不是分销商跳过
+            if(!$v['is_partner']) continue;
+            // 成长值
+            $growth = UserGrowthLog::where('create_at','> time',$last_year)
+                ->where('user_id','=',$v['id'])
+                ->where('growth','>',0)
+                ->sum('growth');
+            // 成长值 过期
+            if($growth < $v['wallet']['growth']) {
+                UserWallet::userGrowthChange($v['id'],$v['wallet']['growth']-$growth,8,'成长值过期',-1);
+                $v['wallet']['growth'] = $growth;
+                // 更新会员
+                UserIdentity::userPartnerLevel($v,$partner_level,$v['id']);
+            }
+        }
+        $this->success('执行'.count($user_list).'条数据');
+    }
+
+
+    // 会员优惠券过期定时
+    public function couponOverTime()
+    {
+        UserCouponList::where([['type','=',1],['end','< time',date('Y-m-d')],['status','=',0]])->update(['status'=>2]);
+    }
+
+}

+ 303 - 0
application/api/controller/Trolley.php

@@ -0,0 +1,303 @@
+<?php
+namespace app\api\controller;
+use app\common\model\StoreGoods;
+use app\common\model\StoreGoodsItem;
+use app\common\model\User;
+use think\Db;
+use app\common\model\ShoppingTrolley;
+use app\common\model\DeliveryAddress;
+use think\Exception;
+
+/**
+ * @title 购物车
+ * @controller Trolley
+ * @group base
+ */
+class Trolley extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+
+    /**
+     * @title 获取购物车商品数量
+     * @desc  获取购物车商品数量
+     * @author  qc
+     * @url /api/Trolley/getTrolleyNum
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param name:goods_id type:int default:-- desc:商品id(商品id不传查全部的)
+     * @return name:total_num type:int default:-- desc:购物车商品数量
+     */
+    public function getTrolleyNum()
+    {
+        $where = [];
+        $where['user_id'] = $this->user_id;
+        if($goods_id = input('get.goods_id',0)) $where['goods_id'] = $goods_id;
+        $total_num = ShoppingTrolley::where($where)->sum('num');
+        $this->success('ok',['total_num'=>$total_num]);
+    }
+
+
+
+    /**
+     * @title 获取购物车列表
+     * @desc  获取购物车列表
+     * @author  qc
+     * @url /api/Trolley/getTrolleyList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_name type:string default:-- desc:商品名称
+     * @return name:goods_status type:int default:-- desc:商品状态(1上架,0下架)
+     * @return name:deleted_status type:string default:-- desc:删除状态(1删除,0未删除)
+     * @return name:item_list type:array default:-- desc:添加该商品的规格列表
+     * @return name:item_list.id type:int default:-- desc:购物车记录id
+     * @return name:item_list.num type:int default:-- desc:数量
+     * @return name:item_list.goods_id type:int default:-- desc:商品id
+     * @return name:item_list.spec_id type:int default:-- desc:规格id
+     * @return name:item_list.goods_no type:int default:-- desc:货号
+     * @return name:item_list.spec_title type:string default:-- desc:规格名称
+     * @return name:item_list.cover type:string default:-- desc:规格封面
+     * @return name:item_list.original_price type:float default:-- desc:规格原价(下划线价格)
+     * @return name:item_list.sell_price type:float default:-- desc:规格售价
+     * @return name:total_num type:int default:-- desc:购物车商品数量
+     */
+    public function getTrolleyList()
+    {
+        $trolley_goods = ShoppingTrolley::field('goods_id')
+            ->where('user_id',$this->user_id)->group('goods_id')
+            ->select();
+        if(!$trolley_goods) $this->success('',['list'=>[]]);
+        $goods_ids = array_column($trolley_goods->toArray(),'goods_id');
+        $list = [];
+        $total_num = 0;
+        $goods_list = StoreGoods::where('id','in',$goods_ids)->select()->toArray();
+        foreach ($goods_list as $goods_info){
+            $trolley_data =  ['goods_id'=>$goods_info['id'],'cover'=>$goods_info['cover'],'goods_name'=>$goods_info['name'],'goods_status'=>$goods_info['status'],'deleted_status'=>$goods_info['is_deleted'],'is_combo'=>$goods_info['is_combo'],'full_money'=>0,'sub_money'=>0];
+            $join_field = 't.id,t.num,t.spec_id,t.goods_id,i.goods_spec,i.cover,i.goods_no,i.spec_title,i.stock,i.is_deleted,i.original_price,i.sell_price,i.weight';
+            $trolley_data['item_list'] = ShoppingTrolley::field($join_field)->alias('t')
+                ->where('t.goods_id',$goods_info['id'])
+                ->leftJoin('StoreGoodsItem i','i.id = t.spec_id')
+                ->select()->toArray();
+            $total_num += array_sum(array_column($trolley_data,'num'));
+            $list[] = $trolley_data;
+        }
+        $this->success('ok',['list'=>$list,'total_num'=>$total_num]);
+    }
+
+    /**
+     * @title 商品添加购物车(按规格加入)
+     * @desc  商品某个规格加入多少
+     * @author  qc
+     * @url /api/Trolley/addTrolley
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:goods_id type:int require:1  default:0 desc:商品id
+     * @param  name:spec_id type:int  require:1 default:0 desc:规格id
+     * @param  name:num type:int default:1 desc:数量
+     */
+    public function addTrolley()
+    {
+        $goods_id = input('post.goods_id');
+        $spec_id = input('post.spec_id');
+        $num    = input('post.num',1);
+        if(!$goods_id || !$spec_id)  $this->error('请选择商品');
+        if($num <=0 ) $this->error('添加数量有误');
+        Db::startTrans();
+        try {
+            // 商品详情
+            $goods_info = StoreGoods::with(['itemList'=>function($query)use($spec_id){
+                return $query->where('id',$spec_id)->where('is_deleted',0);
+            }])->where('id',$goods_id)->where('is_deleted',0)->where('status',1)->find();
+            if(!$goods_info) throw new Exception('商品已下架');
+            $goods_info = $goods_info->toArray();
+            if(empty($goods_info['item_list'])) throw new Exception('该规格已下架');
+            if($goods_info['is_presell']) throw new Exception('预售商品无法加入购物车');
+            if($goods_info['item_list'][0]['stock'] < $num) throw new Exception('库存不足');
+            $trolley_id = ShoppingTrolley::checkTrolley($this->user_id,$goods_id,$spec_id);
+            // 添加到购物车
+            if($trolley_id) {
+                ShoppingTrolley::where('id',$trolley_id)->setInc('num',$num);
+            }else{
+                $trolley_info = [
+                    'user_id' => $this->user_id,
+                    'goods_id' => $goods_id,
+                    'spec_id' => $spec_id,
+                    'goods_no' => $goods_info['item_list'][0]['goods_no'],
+                    'num' => $num,
+                ];
+                ShoppingTrolley::create($trolley_info);
+            }
+            // 扣减库存
+            StoreGoods::where('id',$goods_id)->setDec('stock',$num);
+            StoreGoodsItem::where('id',$spec_id)->setDec('stock',$num);
+            Db::commit();
+        }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg = $e->getMessage();
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('添加成功'):$this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 修改购物车商品数量
+     * @desc  修改购物车商品数量
+     * @author  qc
+     * @url /api/Trolley/changeTrolleyNum
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:trolley_id type:int require:1  default:0 desc:购物车记录id
+     * @return name:num type:int require:1 default:1 desc:变更数量
+     * @return name:type type:intrequire:1 default:1 desc:变更类型(1增加2扣减)
+     */
+    public function changeTrolleyNum()
+    {
+        $trolley_id = input('post.trolley_id');
+        $num = input('post.num',1);
+        $type = input('post.type',1);
+        if(!in_array($type,[1,2])) $this->error('变更可类型错误');
+        Db::startTrans();
+        try {
+            $trolley_info = ShoppingTrolley::get($trolley_id);
+            if(!$trolley_info) $this->exception('记录不存在!');
+            $goods_info = StoreGoods::getGoodsSpec($trolley_info->goods_id,$trolley_info->spec_id);
+            if($type == 1){
+                if(!$goods_info) $this->exception('商品已下架');
+                if(empty($goods_info['item_list'])) $this->exception('该规格已下架');
+                if($goods_info['item_list'][0]['stock'] < $num)$this->exception('库存不足');
+                ShoppingTrolley::where('id',$trolley_id)->setInc('num',$num);
+                StoreGoods::where('id',$trolley_info->goods_id)->setDec('stock',$num);// 扣减商品库存
+                StoreGoodsItem::where('id',$trolley_info->spec_id)->setDec('stock',$num);// 扣减规格库存
+            }else{
+                if($trolley_info->num < $num) $this->exception('扣减数量有误');
+                if($trolley_info->num > $num){
+                    ShoppingTrolley::where('id',$trolley_id)->setDec('num',$num);//扣减数量
+                }else{
+                    ShoppingTrolley::where('id',$trolley_id)->delete();//删除记录
+                }
+                StoreGoods::where('id',$trolley_info->goods_id)->setInc('stock',$num);//增加商品库存
+                StoreGoodsItem::where('id',$trolley_info->spec_id)->setInc('stock',$num);//增加规格库存
+            }
+            Db::commit();
+        }catch (\Exception $e){
+            $this->ret_msg = $e->getMessage();
+            $this->is_commit = false;
+            Db::rollback();
+        }
+        $this->is_commit ? $this->success('操作成功') : $this->error($this->ret_msg);
+    }
+
+    /**
+     * @title 删除购物车记录
+     * @desc  删除购物车记录
+     * @author  qc
+     * @url /api/Trolley/cancelTrolleyList
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:ids type:string require:1  default:0 desc:购物车记录id(多条用逗号隔开)
+     */
+    public function cancelTrolleyList()
+    {
+        $ids = input('post.ids');
+        if(!$ids) $this->error('请选择要删除的数据');
+        $trolley_list = ShoppingTrolley::where('id','in',$ids)->select();
+        Db::startTrans();
+        foreach ($trolley_list as $trolley_info) {
+            StoreGoods::where('id',$trolley_info->goods_id)->setInc('stock',$trolley_info->num);//增加商品库存
+            StoreGoodsItem::where('id',$trolley_info->spec_id)->setInc('stock',$trolley_info->num);//增加规格库存
+        }
+        ShoppingTrolley::where('id','in',$ids)->delete();
+        Db::commit();
+        $this->success('删除成功');
+
+    }
+
+    /**
+     * @title 某商品是否添加到购物
+     * @desc  获取某商品添加到购物车规格及数量
+     * @author  qc
+     * @url /api/Trolley/getTrolleyByGoodsId
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:goods_id type:int  default:1 desc:商品id
+     * @return name:spec_id type:int default:-- desc:规格id
+     * @return name:num type:int default:-- desc:数量
+     */
+    public function getTrolleyByGoodsId()
+    {
+        $goods_id = input('get.goods_id');
+        $list = ShoppingTrolley::field('id,goods_id,spec_id,goods_no,num')
+            ->where(['user_id'=>$this->user_id,'goods_id'=>$goods_id])
+            ->order('id desc')
+            ->select();
+        $this->success('ok',['list'=>$list?$list->toArray() : [] ]);
+    }
+
+
+    /**
+     * @title 购物车订单确认
+     * @desc  购物车订单确认
+     * @author  qc
+     * @url /api/Trolley/confirmTrolleyList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:ids type:int  default:1 desc:购物车记录id(多条用逗号隔开)
+     * @return name:goods_id type:int default:-- desc:商品id
+     * @return name:goods_name type:string default:-- desc:商品名称
+     * @return name:goods_status type:int default:-- desc:商品状态(1上架,0下架)
+     * @return name:deleted_status type:string default:-- desc:删除状态(1删除,0未删除)
+     * @return name:item_list type:array default:-- desc:添加该商品的规格列表
+     * @return name:item_list.spec_id type:int default:-- desc:规格id
+     * @return name:item_list.goods_no type:int default:-- desc:货号
+     * @return name:item_list.goods_spec type:array default:-- desc:规格详情
+     * @return name:item_list.goods_spec.spec_title type:string default:-- desc:规格名称
+     * @return name:item_list.goods_spec.cover type:string default:-- desc:规格封面
+     * @return name:item_list.goods_spec.original_price type:float default:-- desc:规格原价
+     * @return name:item_list.goods_spec.sell_price type:float default:-- desc:规格售价
+     * @return name:wallet type:float default:-- desc:金额
+     * @return name:address_info type:array default:-- desc:默认收货地址
+     * @return name:wallet type:array default:-- desc:钱包
+     * @return name:walle.integral type:int default:-- desc:积分
+     * @return name:walle.money type:int default:-- desc:佣金余额
+     */
+    public function confirmTrolleyList()
+    {
+        $ids = input('get.ids');
+        $trolley_goods = ShoppingTrolley::field('goods_id')
+            ->where('user_id',$this->user_id)
+            ->where('id','in',$ids)
+            ->group('goods_id')
+            ->select();
+        if(!$trolley_goods) $this->error('请选择商品');
+        $goods_ids = array_column($trolley_goods->toArray(),'goods_id');
+        $list = [];
+        $total_money = 0;
+        $goods_list = StoreGoods::where('id','in',$goods_ids)->select()->toArray();
+        foreach ($goods_list as $goods_info){
+            $trolley_data =  ['goods_id'=>$goods_info['id'],'goods_name'=>$goods_info['name'],'goods_status'=>$goods_info['status'],'deleted_status'=>$goods_info['is_deleted'],'is_combo'=>$goods_info['is_combo']];
+            $trolley_data['item_list'] = ShoppingTrolley::with(['goodsSpec'])->where('id','in',$ids)->where('goods_id',$goods_info['id'])->select()->toArray();
+            foreach ($trolley_data['item_list'] as $iv){
+                $total_money = bcadd(bcmul($iv['num'],$iv['goods_spec']['sell_price'],2),$total_money,2);
+            }
+            $list[] = $trolley_data;
+        }
+        $address_info = DeliveryAddress::where(['user_id'=>$this->user_id,'is_mr'=>1])->find();
+        $user_info = User::with('wallet')->field('id,level_id')->where('id',$this->user_id)->find()->toArray();
+        $this->success('ok',[
+            'list'=>$list,
+            'total_money'=>$total_money,
+            'address_info'=>$address_info ? $address_info->toArray():'',
+            'wallet'=>$user_info['wallet'],
+            ]);
+
+    }
+
+
+
+
+}

+ 151 - 0
application/api/controller/Upload.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\api\controller;
+
+use app\common\controller\Api;
+use library\File;
+
+/**
+ * @title OSS对象存储
+ * @controller Upload
+ * @group common
+ */
+class Upload extends Base
+{
+    protected $id ;
+    protected $key;
+    protected $host;
+
+
+    public function initialize(){
+       $this->id =   config('app.ali_set.Key');
+       $this->key =  config('app.ali_set.secret');
+       $this->host = config('app.ali_set.host');
+    }
+
+
+    public function upload()
+    {
+        if (!($file = $this->getUploadFile()) || empty($file)) {
+            $this->error('文件上传异常,文件可能过大或未上传!');
+        }
+        if (!$file->checkExt(strtolower(sysconf('storage_local_exts')))) {
+            $this->error('文件上传类型受限,请在后台配置!');
+        }
+        if ($file->checkExt('php,sh')) {
+            $this->error('可执行文件禁止上传到本地服务器!');
+        }
+        $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'])) {
+            $url = $this->safe ? $name : $info['url'];
+            $this->success('上传成功',$url);
+        } else {
+            $this->error('文件处理失败,请稍候再试!');
+        }
+    }
+    /**
+     * 获取本地文件对象
+     * @return \think\File
+     */
+    private function getUploadFile()
+    {
+        try {
+            return $this->request->file('file');
+        } catch (\Exception $e) {
+            $this->error(lang($e->getMessage()));
+        }
+    }
+
+    /**
+     * 获取文件上传方式
+     * @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;
+    }
+    /**
+     * @title 获取配置
+     * @desc 获取配置
+     * @author QGF
+     * @url /api/Upload/getSignedUrl
+     * @method GET
+     * @tag 配置信息
+     * @param name:type type:string require:1 default:-- desc:
+     */
+    public function getSignedUrl(){
+
+        $type=$this->request->get('type');
+        $data=$this->getPolicy($type.'/');
+        $this->success('操作成功',$data);
+    }
+
+    public function getPolicy($path,$maxSize=5000000){
+        $now = time();
+        $expire = 600; //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问
+        $end = $now + $expire;
+        $expiration = $this->_gmt_iso8601($end);
+        $policy = [
+            'expiration'=>$expiration,
+            'conditions'=>[
+                ['content-length-range', 1, $maxSize],
+                ['starts-with', '$key', $path],
+            ]
+        ];
+        $policy = json_encode($policy);
+        $policy = base64_encode($policy);
+        $signature = base64_encode(hash_hmac('sha1', $policy, $this->key, true));
+
+        $response = array();
+        $response['OSSAccessKeyId'] = $this->id;
+        $response['policy'] = $policy;
+        $response['Signature'] = $signature;
+        $response['host'] = $this->host;
+        $response['expire'] = $end;
+        $response['success_action_status'] = 200;
+        //这个参数是设置用户上传指定的前缀
+        $response['key'] = $path;
+        return $response;
+    }
+    protected function _gmt_iso8601($time) {
+        $dtStr = date("c", $time);
+        $mydatetime = new \DateTime($dtStr);
+        $expiration = $mydatetime->format(\DateTime::ISO8601);
+        $pos = strpos($expiration, '+');
+        $expiration = substr($expiration, 0, $pos);
+        return $expiration."Z";
+    }
+
+
+    public function getSysDirection()
+    {
+        $data = [
+            'film_notice'=>htmlspecialchars_decode(sysconf('film_notice')),
+            'film_direction'=>htmlspecialchars_decode(sysconf('film_direction'))
+        ];
+        $this->success('获取成功',$data);
+    }
+}

+ 488 - 0
application/api/controller/UserCenter.php

@@ -0,0 +1,488 @@
+<?php
+namespace app\api\controller;
+use app\common\model\GoodsOrder;
+use app\common\model\UserCollect;
+use app\common\model\UserCouponList;
+use app\common\model\UserLevel;
+use app\common\model\UserTrack;
+use app\common\validate\UserVali;
+use think\Db;
+use app\common\model\UserBank;
+use app\common\model\User;
+/**
+ * @title 会员个人中心
+ * @controller UserCenter
+ * @group base
+ */
+class UserCenter extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 获取个人信息(不含统计)
+     * @desc 个人信息
+     * @author qc
+     * @url /api/User_center/getPureUserInfo
+     * @method GET
+     * @tag 个人信息
+     * @header name:Authorization require:1 desc:Token
+     * @return name:phone type:int default:-- desc:手机号
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:encryption_password type:string default:-- desc:加密密码
+     * @return name:headimg type:string default:-- desc:头像地址
+     * @return name:sex type:int default:1 desc:性别(1男2女)
+     * @return name:true_name type:string default:-- desc:真实姓名
+     * @return name:invite_code type:string default:-- desc:邀请码
+     * @return name:birthday type:string default:-- desc:出生日期
+     * @return name:province_name type:string default:-- desc:省
+     * @return name:city_name type:string default:-- desc:市
+     * @return name:counties_name type:string default:-- desc:县区
+     * @return name:bind_wechat type:string default:-- desc:绑定微信号
+     * @return name:true_name type:string default:-- desc:真实姓名
+     * @return name:id_card type:string default:-- desc:身份证号
+     * @return name:is_auth type:int default:-- desc:是否认证(0否1是)
+     * @return name:auth_at type:string default:-- desc:认证时间
+     * @return name:card_front type:string default:-- desc:身份证正面
+     * @return name:card_back type:string default:-- desc:身份证背面
+     * @return name:level_name type:string default:-- desc:等级名称
+     * @return name:wallet type:array default:-- desc:钱包
+     * @return name:wallet.integral type:int default:-- desc:积分
+     * @return name:wallet.growth type:int default:-- desc:经验值(成长值)
+     * @return name:wallet.money type:float default:-- desc:佣金
+     * @return name:order_stat type:array default:-- desc:订单统计
+     *
+     */
+    public function getPureUserInfo()
+    {
+        $field = 'id,phone,encryption_password,name,level_id,pay_password,headimg,openid,true_name,sex,invite_code,birthday,province_name,city_name,counties_name,bind_wechat,id_card,card_front,card_back,auth_at,is_agency,partner_lev';
+        $user_info = User::with('wallet')->field($field)->where('id',$this->user_id)->find()->toArray();
+        if(empty($user_info)) $this->error('用户信息不正确');
+        $user_info['level_name'] = UserLevel::where('id',$user_info['level_id'])->value('name');
+        $this->success('获取成功',['detail'=>$user_info,]);
+    }
+
+
+    /**
+     * @title 获取个人信息
+     * @desc 个人信息
+     * @author qc
+     * @url /api/User_center/getUserInfo
+     * @method GET
+     * @tag 个人信息
+     * @header name:Authorization require:1 desc:Token
+     * @return name:phone type:int default:-- desc:手机号
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:encryption_password type:string default:-- desc:加密密码
+     * @return name:headimg type:string default:-- desc:头像地址
+     * @return name:sex type:int default:1 desc:性别(1男2女)
+     * @return name:true_name type:string default:-- desc:真实姓名
+     * @return name:invite_code type:string default:-- desc:邀请码
+     * @return name:birthday type:string default:-- desc:出生日期
+     * @return name:province_name type:string default:-- desc:省
+     * @return name:city_name type:string default:-- desc:市
+     * @return name:counties_name type:string default:-- desc:县区
+     * @return name:bind_wechat type:string default:-- desc:绑定微信号
+     * @return name:true_name type:string default:-- desc:真实姓名
+     * @return name:id_card type:string default:-- desc:身份证号
+     * @return name:is_auth type:int default:-- desc:是否认证(0否1是)
+     * @return name:auth_at type:string default:-- desc:认证时间
+     * @return name:card_front type:string default:-- desc:身份证正面
+     * @return name:card_back type:string default:-- desc:身份证背面
+     * @return name:level_name type:string default:-- desc:等级名称
+     * @return name:partner_lev type:int default:-- desc:分销商等级id(0不是分销商)
+     * @return name:is_agency type:int default:-- desc:是否是区域代理(0不是)
+     * @return name:fans type:int default:-- desc:粉丝数量
+     * @return name:collect type:int default:-- desc:收藏量
+     * @return name:coupon_num type:int default:-- desc:券数量
+     * @return name:track_num type:int default:-- desc:足迹条数
+     * @return name:wallet type:array default:-- desc:钱包
+     * @return name:wallet.integral type:int default:-- desc:积分
+     * @return name:wallet.growth type:int default:-- desc:经验值(成长值)
+     * @return name:wallet.money type:float default:-- desc:佣金
+     * @return name:order_stat type:array default:-- desc:订单统计
+     * @return name:order_stat.no_pay type:int default:-- desc:未支付订单
+     * @return name:order_stat.no_deliver type:int default:-- desc:未发货
+     * @return name:order_stat.no_receive type:int default:-- desc:未收货
+     * @return name:order_stat.no_comment type:int default:-- desc:未评论
+     *
+     */
+    public function getUserInfo()
+    {
+        $field = 'id,phone,encryption_password,name,level_id,pay_password,headimg,openid,true_name,sex,invite_code,birthday,province_name,city_name,counties_name,bind_wechat,id_card,card_front,card_back,auth_at,is_agency,partner_lev';
+        $user_info = User::with('wallet')->field($field)->where('id',$this->user_id)->find()->toArray();
+        $user_info['level_name'] = UserLevel::where('id',$user_info['level_id'])->value('name');
+        $user_info['fans'] = User::where('pid',$user_info['id'])->count();
+        $user_info['collect'] = UserCollect::where('user_id',$user_info['id'])->count();
+        $user_info['coupon_num'] = UserCouponList::where(['user_id'=>$user_info['id'],'status'=>0])->count();
+        $user_info['track_num'] = UserTrack::where(['user_id'=>$user_info['id']])->count();
+        $order_stat = [];
+        $order_stat['no_pay']    = GoodsOrder::where(['user_id'=>$this->user_id,'status'=>0])->count();
+        $order_stat['no_deliver'] = GoodsOrder::where(['user_id'=>$this->user_id,'status'=>1])->count();
+        $order_stat['no_receive'] = GoodsOrder::where(['user_id'=>$this->user_id,'status'=>2])->count();
+        $order_stat['no_comment '] = GoodsOrder::where(['user_id'=>$this->user_id,'status'=>3])->count();
+        if(empty($user_info)) $this->error('用户信息不正确');
+        $this->success('获取成功',['detail'=>$user_info,'order_stat'=>$order_stat]);
+    }
+
+    /**
+     * @title 编辑个人信息
+     * @desc 编辑个人信息
+     * @author qc
+     * @url /api/User_center/updateUserInfo
+     * @method POST
+     * @tag 编辑信息
+     * @header name:Authorization require:1 desc:Token
+     * @param name:name type:string default:-- desc:昵称
+     * @param name:headimg type:string default:-- desc:头像地址
+     * @param name:sex type:int default:1 desc:性别(1男2女)
+     * @param name:birthday type:string default:1 desc:出生日期
+     * @param name:address type:string default:1 desc:地址(山东省-临沂市-兰山区)
+     */
+    public function updateUserInfo()
+    {
+        $headimg    = input('post.headimg');
+        $name       = trim(input('post.name',''));
+        $sex        = trim(input('post.sex',1));
+        $birthday   = input('post.birthday');
+        $address    = input('post.address');
+        $update_data= [];
+        $update_data['name']        = $name;
+        $update_data['headimg']     = $headimg;
+        $update_data['sex']         = $sex;
+        $update_data['birthday']    = $birthday;
+        if($address){
+            $add_arr = explode('-',$address);
+            $update_data['province_name'] = $add_arr[0];
+            $update_data['city_name'] = $add_arr[1];
+            $update_data['counties_name'] = $add_arr[2];
+        }
+        if($name){
+            $check_member =  Db::name('store_member')->where('name',$name)->where('id','<>',$this->user_id)->count();
+            if($check_member) $this->error('该用户名已被占用');
+        }
+        Db::name('store_member')->where('id',$this->user_id)->update($update_data);
+        $field = 'phone,name,headimg';
+        $user_info = Db::name('store_member')->field($field)->where('id',$this->user_id)->find();
+        $this->success('编辑成功',$user_info);
+    }
+
+    /**
+     * @title 绑定手机号
+     * @desc  绑定手机号
+     * @author  qc
+     * @url /api/User_center/modifyPhone
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:int require:1 default:-- desc:手机号验证码
+     * @return name:phone type:int default:-- desc:手机号
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:headimg type:string default:-- desc:头像地址
+     * @return name:true_name type:string default:-- desc:真实姓名
+     * @return name:id_card type:string default:-- desc:身份证号
+     * @return name:is_auth type:int default:-- desc:是否认证(0否1是)
+     */
+    public function modifyPhone()
+    {
+        $uid = $this->user_id;
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        if(empty($phone) || empty($code) ) $this->error('参数错误');
+        $field = 'id,phone,name,headimg,status,openid,true_name,id_card,is_auth';
+        $user_info = Db::name('store_member')->field($field)->where('id',$this->user_id)->find();
+        if($user_info['phone'] == $phone)$this->error('更换手机号与绑定手机号一致!');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        //判断手机号是否已注册
+        $member_id = Db::name('store_member')
+            ->where('phone','=',$phone)->where('is_deleted','=',0)->where('id','<>',$this->user_id)->value('id');
+        if($member_id)  $this->error('手机号已注册过');
+        Db::name('store_member')->where('id',$uid)->update(['phone'=>$phone]);
+        $user_info['phone'] = $phone;
+        $this->updatePhoneCode($check_code);
+        $this->success('绑定成功',$user_info);
+    }
+
+    /**
+     * @title 验证已绑定手机号是否正确
+     * @desc  验证已绑定手机号是否正确
+     * @author  qc
+     * @url /api/User_center/checkBindPhone
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:int require:1 default:-- desc:手机号验证码
+     */
+    public function checkBindPhone()
+    {
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        if(empty($phone) || empty($code) ) $this->error('参数错误');
+        $field = 'id,phone,name,headimg,status,openid,true_name,id_card,is_auth';
+        $user_info = Db::name('store_member')->field($field)->where('id',$this->user_id)->find();
+        if($user_info['phone'] != $phone) $this->error('该手机号与当前账户不一致!');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $this->updatePhoneCode($check_code);
+        $this->success('验证通过');
+    }
+
+    /**
+     * @title 更换或设置登录密码
+     * @desc  更换或设置登录密码
+     * @author  qc
+     * @url /api/User_center/modifyPassword
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:int require:1 default:-- desc:手机号验证码
+     * @param name:password type:string default:-- desc:密码
+     */
+    public function modifyPassword()
+    {
+        $uid = $this->user_id;
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        $password  = input('post.password');
+        if(empty($phone) || empty($code) || empty($password) ) $this->error('参数错误');
+        $field = 'id,phone';
+        $user_info = User::field($field)->where('id',$this->user_id)->find()->toArray();
+        if(!$user_info['phone']) $this->error('请先绑定手机号');
+        if($user_info['phone'] != $phone) $this->error('与绑定手机号不一致');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $validate = new UserVali();
+        if (!$validate->scene('reset_password')->check(['phone'=>$phone,'password'=>$password])) {
+            $this->error($validate->getError());
+        }
+        $encryption_password = encrypt_password($password);
+        User::where('id',$uid)->update(['password'=>$password,'encryption_password'=>$encryption_password]);
+        $this->updatePhoneCode($check_code);
+        $this->success('更换成功');
+    }
+
+
+    /**
+     * @title 更换或设置提现密码
+     * @desc  更换或设置提现密码
+     * @author  qc
+     * @url /api/User_center/setPayPassword
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:phone type:int require:1 default:-- desc:手机号
+     * @param name:code type:int require:1 default:-- desc:手机号验证码
+     * @param name:pay_password type:string default:-- desc:密码
+     */
+    public function setPayPassword()
+    {
+        $uid = $this->user_id;
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        $pay_password  = input('post.pay_password');
+        if(empty($phone) || empty($code) || empty($pay_password)) $this->error('参数错误');
+        $field = 'id,phone';
+        $user_info = User::field($field)->where('id',$this->user_id)->find()->toArray();
+        if(!$user_info['phone']) $this->error('请先绑定手机号');
+        if($user_info['phone'] != $phone) $this->error('与绑定手机号不一致');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');;
+        User::where('id',$uid)->update(['pay_password'=>encrypt_password($pay_password)]);
+        $this->updatePhoneCode($check_code);
+        $this->success('更换成功');
+    }
+
+
+    /**
+     * @title 实名认证
+     * @desc 实名认证
+     * @author qc
+     * @method POST
+     * @tag 实名认证
+     * @url /api/User_center/userCertification
+     * @header name:Authorization require:1 desc:Token
+     * @param name:true_name type:string require:1 default:-- desc:真实姓名
+     * @param name:id_card type:string require:1 default:-- desc:身份证号
+     * @param name:card_front type:string require:1 default:-- desc:身份证正面
+     * @param name:card_back type:string require:1 default:-- desc:身份证反面
+     */
+    public function userCertification()
+    {
+        $true_name = input('post.true_name');
+        $id_card = input('post.id_card');
+        $card_front = input('post.card_front');
+        $card_back = input('post.card_back');
+        $is_auth =User::where('id',$this->user_id)->value('is_auth');
+        if($is_auth) $this->error('已认证');
+        $get_age = get_age($id_card);
+        if($get_age < 18)$this->error('未满18周岁!');
+        $res = user_certification($id_card,$true_name);
+        if(!$res) $this->error('认证失败');
+        User::where('id',$this->user_id)->update(['is_auth'=>1,'true_name'=>$true_name,'card_front'=>$card_front,'card_back'=>$card_back,'id_card'=>$id_card,'auth_at'=>date('Y-m-d H:i:s')]);
+        $this->success('认证成功');
+    }
+
+    /**
+     * @title 注销会员
+     * @desc 注销会员
+     * @author qc
+     * @method POST
+     * @url /api/User_center/cancelUserInfo
+     * @header name:Authorization require:1 desc:Token
+     */
+    public function cancelUserInfo()
+    {
+        Db::name('store_member')->where('id',$this->user_id)->update(['is_deleted'=>1]);
+        $this->success('注销成功');
+    }
+
+    /**
+     * @title 获取我绑定的支付宝账户
+     * @desc 获取我绑定的支付宝账户
+     * @author qc
+     * @method GET
+     * @url /api/User_center/getMyAliAccount
+     * @return name:birthday type:string default:-- desc:出生日期
+     * @return name:real_name type:string default:-- desc:姓名
+     * @return name:card_no type:string default:-- desc:账号
+     */
+    public function getMyAliAccount()
+    {
+        $ali_account = UserBank::field('id,real_name,card_no')->where(['user_id'=>$this->user_id,'type'=>1,'is_deleted'=>0])->find();
+        $ali_account ? $this->success('ok',['account'=>$ali_account->toArray()]) : $this->error('还没有绑定支付宝账户');
+    }
+
+    /**
+     * @title 更改或绑定支付宝账户
+     * @desc 更改或绑定支付宝账户
+     * @author qc
+     * @method POST
+     * @url /api/User_center/bindAliAccount
+     * @param name:phone type:string require:1 default:-- desc:手机号
+     * @param name:code type:string require:1 default:-- desc:验证码
+     * @param name:real_name type:string require:1 default:-- desc:真实姓名
+     * @param name:card_no type:string require:1 default:-- desc:账号
+     */
+    public function bindAliAccount()
+    {
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        $real_name  = input('post.real_name');
+        $card_no  = input('post.card_no');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        $ali_account = UserBank::where(['user_id'=>$this->user_id,'type'=>1,'is_deleted'=>0])->find();
+        if(!$ali_account){
+            $account_data =[
+                'user_id' => $this->user_id,
+                'real_name' => $real_name,
+                'bank_name' => '支付宝账号',
+                'card_no' => $card_no,
+                'create_time' =>  date('Y-m-d H:i:s'),
+            ];
+            UserBank::create($account_data);
+        }else{
+            $account_data =[
+                'user_id' => $this->user_id,
+                'real_name' => $real_name,
+                'bank_name' => '支付宝账号',
+                'card_no' => $card_no,
+                'update_time' =>  date('Y-m-d H:i:s'),
+            ];
+            UserBank::update($account_data,['id'=>$ali_account->id]);
+        }
+       $this->success('绑定成功');
+
+    }
+
+
+
+
+
+    /**
+     * @title 更改或绑定银行卡
+     * @desc 更改或绑定银行卡
+     * @author qc
+     * @method POST
+     * @url /api/User_center/bindBankAccount
+     * @param name:account_id type:string require:1 default:-- desc:记录id(修改时必传)
+     * @param name:phone type:string require:1 default:-- desc:手机号
+     * @param name:code type:string require:1 default:-- desc:验证码
+     * @param name:real_name type:string require:1 default:-- desc:真实姓名
+     * @param name:card_no type:string require:1 default:-- desc:账号
+     * @param name:bank_name type:string require:1 default:-- desc:所属银行
+     */
+    public function bindBankAccount()
+    {
+        $phone = input('post.phone');
+        $code  = input('post.code');
+        $real_name  = input('post.real_name');
+        $card_no  = input('post.card_no');
+        $bank_name  = input('post.bank_name');
+        $account_id  = input('post.account_id');
+        $check_code = $this->checkPhoneCode($phone,$code);
+        if(!$check_code) $this->error('验证码错误');
+        if(!$account_id){
+            $account_data =[
+                'user_id' => $this->user_id,
+                'type' => 2,
+                'real_name' => $real_name,
+                'bank_name' => $bank_name,
+                'card_no' => $card_no,
+                'create_time' =>  date('Y-m-d H:i:s'),
+            ];
+            UserBank::create($account_data);
+        }else{
+            $account_data =[
+                'user_id' => $this->user_id,
+                'real_name' => $real_name,
+                'bank_name' => $bank_name,
+                'card_no' => $card_no,
+                'update_time' =>  date('Y-m-d H:i:s'),
+            ];
+            UserBank::update($account_data,['id'=>$account_id]);
+        }
+        $this->success('绑定成功');
+
+    }
+
+    /**
+     * @title 获取绑定银行卡详情
+     * @desc 获取绑定银行卡详情
+     * @author qc
+     * @method GET
+     * @url /api/User_center/getBandAccountDetail
+     * @param name:account_id type:string require:1 default:-- desc:id
+     * @return name:real_name type:string require:1 default:-- desc:真实姓名
+     * @return name:card_no type:string require:1 default:-- desc:账号
+     * @return name:bank_name type:string require:1 default:-- desc:所属银行
+     */
+    public function getBandAccountDetail()
+    {
+        $account_id = input('get.account_id');
+        $account_info = UserBank::field('id,real_name,card_no,bank_name')->where(['user_id'=>$this->user_id,'id'=>$account_id,'is_deleted'=>0])->find();
+        $account_info ? $this->success('ok',['account'=>$account_info->toArray()]) : $this->error('没找到记录');
+    }
+
+    /**
+     * @title 获取绑定银行卡列表
+     * @desc 获取绑定银行卡列表
+     * @author qc
+     * @method GET
+     * @url /api/User_center/getBankAccountList
+     * @return name:real_name type:string require:1 default:-- desc:真实姓名
+     * @return name:card_no type:string require:1 default:-- desc:账号
+     * @return name:bank_name type:string require:1 default:-- desc:所属银行
+     */
+    public function getBankAccountList()
+    {
+        $list = UserBank::field('id,real_name,card_no,bank_name')->where(['user_id'=>$this->user_id,'type'=>2,'is_deleted'=>0])->order('id desc')->select();
+        $this->success('ok',['list'=>$list ? $list->toArray() : []]);
+    }
+
+
+
+}

+ 135 - 0
application/api/controller/UserCoupon.php

@@ -0,0 +1,135 @@
+<?php
+namespace app\api\controller;
+use app\common\model\CouponConfig;
+use app\common\model\UserCouponList;
+use think\Db;
+/**
+ * @title 会员优惠券
+ * @controller UserCoupon
+ * @group base
+ */
+class UserCoupon extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 获取所有的优惠券
+     * @desc 获取所有的优惠券
+     * @author qc
+     * @method GET
+     * @url /api/User_coupon/getAllCouponList
+     * @param name:status type:string require:1 default:-1 desc:状态 (-1全部,0:未使用 1:已使用 2:已到期)
+     * @return name:id type:int default:-- desc:会员优惠券记录id
+     * @return name:coupon_type type:int default:-- desc:优惠券类型0全场券1商品券
+     * @return name:goods_id type:int  default:-- desc:商品id
+     * @return name:title type:int  default:-- desc:标题
+     * @return name:low_amount type:float default:-- desc:最低消费限制
+     * @return name:amount type:float default:-- desc:券额
+     * @return name:type type:int default:-- desc:0不限制使用时间1限制使用时间
+     * @return name:start type:string default:-- desc:开始使用时间
+     * @return name:end type:string default:-- desc:结束使用时间
+     * @return name:status type:int default:-- desc:状态 (0:未使用 1:已使用 2:已到期)
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:coupon_set type:array default:-- desc:券详情
+     * @return name:coupon_set.status type:string default:-- desc:0禁用1正常
+     * @return name:coupon_set.is_deleted type:string default:-- desc:删除
+     */
+    public function getAllCouponList()
+    {
+        $status = input('get.status',-1);
+        $where = [];
+        $where['user_id']=$this->user_id;
+        if($status >=0)  $where['status']=$status;
+        $list =  UserCouponList::with('couponSet')
+            ->where($where)->order('id desc')
+            ->select();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 领取优惠券
+     * @desc 领取优惠券
+     * @author qc
+     * @method POST
+     * @url /api/User_coupon/getCoupon
+     * @param name:coupon_id type:string require:1 default:-- desc:券id
+     * @return  name:id type:int require:1 default:-- desc:会员优惠券记录id
+     */
+    public function getCoupon()
+    {
+        $coupon_id = input('post.coupon_id');
+        $coupon_info = CouponConfig::where(['id'=>$coupon_id,'is_deleted'=>'0'])->find();
+        if(!$coupon_info)  $this->error('优惠券不存在');
+        $coupon_info = $coupon_info->toArray();
+        if($coupon_info['status'] != 1 ) $this->error('优惠券已禁用');
+        $count = UserCouponList::where('config_id',$coupon_id)->where('user_id',$this->user_id)->count();
+        $all_send = UserCouponList::where('config_id',$coupon_id)->count();// 总共发放了多少
+        if($coupon_info['num'] > 0 &&  $all_send >=  $coupon_info['num']) $this->error('已发放完');
+        if($count + 1 >  $coupon_info['user_num']) $this->error('已领取');
+        // 领取的详情
+        $data['config_id']=$coupon_info['id'];
+        $data['user_id']=$this->user_id;
+        $data['goods_id']= $coupon_info['goods_id'];
+        $data['title'] = $coupon_info['title'];
+        $data['low_amount']=$coupon_info['low_amount'];
+        $data['amount']=$coupon_info['amount'];
+        if($coupon_info['time_type']==0){
+            if($coupon_info['low_day']==0){
+                $data['type']=0;
+            }else{
+                $data['type']=1;
+                $data['start']=date('Y-m-d');
+                $data['end']=date('Y-m-d', strtotime('+'.$coupon_info['low_day'].' days') );;
+            }
+        }else{
+            $data['type']=1;
+            $data['start']=$coupon_info['start_tm'];
+            $data['end']=$coupon_info['end_tm'];
+        }
+        $data['status']=0;
+        $data['create_at']=time();
+        $data['coupon_type']=$coupon_info['coupon_type'];
+        $res = UserCouponList::create($data);
+        $this->success('领取成功',['id'=>$res->id]);
+
+    }
+
+
+    /**
+     * @title 我的优惠券记录详情
+     * @desc 我的优惠券记录详情
+     * @author qc
+     * @method GET
+     * @url /api/User_coupon/getCouponInfo
+     * @param name:id type:string require:1 default:-- desc:记录id
+     * @return name:id type:int default:-- desc:会员优惠券记录id
+     * @return name:coupon_type type:int default:-- desc:优惠券类型0全场券1商品券
+     * @return name:goods_id type:int  default:-- desc:商品id
+     * @return name:title type:int  default:-- desc:标题
+     * @return name:low_amount type:float default:-- desc:最低消费限制
+     * @return name:amount type:float default:-- desc:券额
+     * @return name:type type:int default:-- desc:0不限制使用时间1限制使用时间
+     * @return name:start type:string default:-- desc:开始使用时间
+     * @return name:end type:string default:-- desc:结束使用时间
+     * @return name:status type:int default:-- desc:状态 (0:未使用 1:已使用 2:已到期)0:未使用 1:已使用 2:已到期
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:coupon_set type:array default:-- desc:券详情
+     * @return name:coupon_set.status type:string default:-- desc:0禁用1正常
+     * @return name:coupon_set.is_deleted type:string default:-- desc:删除
+     */
+    public function getCouponInfo()
+    {
+        $id = input('get.id');
+        $detail =  UserCouponList::with('couponSet')->where('id',$id)->where('user_id',$this->user_id)->find();
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+
+
+
+
+}

+ 337 - 0
application/api/controller/UserManage.php

@@ -0,0 +1,337 @@
+<?php
+
+
+namespace app\api\controller;
+use app\common\model\DeliveryAddress;
+use app\common\model\UserLevel;
+use think\Db;
+use app\common\model\User;
+use app\common\model\InviteInfo;
+/**
+ * @title 会员管理
+ * @controller UserManage
+ * @group base
+ */
+class UserManage extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+
+    /**
+     * @title 设置收货地址(新增或修改)
+     * @desc  设置收货地址(新增或修改)
+     * @author  qc
+     * @url /api/User_manage/setDeliveryAddress
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int  : default:0 desc:收货地址记录id(不传值是添加)
+     * @param  name:pro_name type:int  require:1  default:-- desc:省名
+     * @param  name:city_name type:int  require:1  default:-- desc:市名
+     * @param  name:county_name type:int  require:1  default:-- desc:县区名
+     * @param  name:street_name type:int  require:1  default:-- desc:街道
+     * @param  name:detail type:string  require:1  default:-- desc:详细地址
+     * @param  name:phone type:string  require:1  default:-- desc:联系电话
+     * @param  name:name type:string  require:1  default:-- desc:联系人
+     * @param  name:is_mr type:int  require:0  default:0 desc:是否是默认(0不默认,1默认)
+     */
+    public function  setDeliveryAddress()
+    {
+        $pro_name     = input('post.pro_name');// 省
+        $city_name    = input('post.city_name');// 市
+        $county_name  = input('post.county_name');// 县区
+        $street_name  = input('post.street_name');// 县区
+        $pro_id     = Db::name('store_area')->where('name',$pro_name)->value('id');
+        $city_id    = Db::name('store_area')->where('name',$city_name)->value('id');
+        $county_id  = Db::name('store_area')->where('name',$county_name)->value('id');
+        $detail     = input('post.detail');// 详细地址
+        $phone      = input('post.phone');
+        $name       = input('post.name');
+        $id         = input('post.id');
+        $is_mr      = input('post.is_mr',0);
+        $set_data =  compact(['pro_id','city_id','county_id','detail','phone','name','is_mr']);
+        $set_data['user_id']    = $this->user_id;
+        $set_data['pro_name']   = $pro_name;
+        $set_data['city_name']  = $city_name;
+        $set_data['county_name']= $county_name;
+        $set_data['street_name']= $street_name;
+        $set_data['mer_name']=$pro_name . $city_name. $county_name;
+        if($id) {
+            Db::name('delivery_address')->where(['id'=>$id])->update($set_data);
+        }else{
+            Db::name('delivery_address')->insert($set_data);
+            $id = Db::getLastInsID();
+        }
+        if($is_mr) Db::name('delivery_address')->where('user_id','=',$this->user_id)->where('id','<>',$id)->where('is_mr','=',1)->update(['is_mr'=>0]);
+        $this->success('编辑成功');
+    }
+
+    /**
+     * @title 修改默认收货地址
+     * @desc  修改默认收货地址
+     * @author  qc
+     * @url /api/User_manage/changeApproveDelivery
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:id type:int default:0 desc:收货地址记录id
+     * @param name:is_mr type:int  default:1 desc:是否是默认(0不默认,1默认)
+     */
+    public function changeApproveDelivery()
+    {
+        $id         = input('post.id');
+        $is_mr      = input('post.is_mr',1);
+        if($is_mr) {
+            Db::name('delivery_address')
+                ->where('user_id','=',$this->user_id)
+                ->where('is_mr','=',1)
+                ->update(['is_mr'=>0]);
+            Db::name('delivery_address')
+                ->where('user_id','=',$this->user_id)
+                ->where('id','=',$id)
+                ->update(['is_mr'=>1]);
+        }else{
+            Db::name('delivery_address')
+                ->where('user_id','=',$this->user_id)
+                ->where('id','=',$id)
+                ->update(['is_mr'=>0]);
+        }
+        $this->success('修改成功');
+    }
+
+    /**
+     * @title 删除收货地址
+     * @desc  删除收货地址
+     * @author  qc
+     * @url /api/User_manage/delDeliveryAddress
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int  require:1 default:1 desc:收货地址记录id
+     */
+    public function delDeliveryAddress()
+    {
+        $id = input('post.id');
+        if(!$id)$this->error('请选择要删除的收货地址');
+        Db::name('delivery_address')->where(['user_id'=>$this->user_id,'id'=>$id])->update(['is_deleted'=>1,'is_mr'=>0]);
+        $this->success('删除成功!');
+    }
+
+    /**
+     * @title 获取收货地址列表
+     * @desc  获取收货地址列表
+     * @author  qc
+     * @url /api/User_manage/getDeliveryAddressList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int   default:1 desc:页数
+     * @param  name:page_num type:int   default:20 desc:每页数
+     * @return name:pro_id type:int   default:-- desc:省id
+     * @return name:city_id type:int   default:-- desc:市id
+     * @return name:county_id type:int  default:-- desc:县区id
+     * @return name:pro_name type:string  default:-- desc:省名
+     * @return name:city_name type:string  default:-- desc:市名
+     * @return name:county_name type:string  default:-- desc:县区名
+     * @return name:street_name type:string  default:-- desc:街道名称
+     * @return name:detail type:string  default:-- desc:详细地址
+     * @return name:phone type:string  default:-- desc:联系电话
+     * @return name:name type:string   default:-- desc:联系人
+     * @return name:is_mr type:int   default:0 desc:是否是默认(0不默认,1默认)
+     */
+    public function getDeliveryAddressList()
+    {
+        $list = DeliveryAddress::where(['user_id'=>$this->user_id,'is_deleted'=>0])
+            ->order('is_mr desc ,id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+
+    }
+
+    /**
+     * @title 获取收货地址详情
+     * @desc  获取收货地址详情
+     * @author  qc
+     * @url /api/User_manage/getDeliveryAddressDetail
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int   default:1 desc:收货地址记录id
+     * @return name:pro_id type:int   default:-- desc:省id
+     * @return name:city_id type:int   default:-- desc:市id
+     * @return name:county_id type:int  default:-- desc:县区id
+     * @return name:pro_name type:string  default:-- desc:省名
+     * @return name:city_name type:string  default:-- desc:市名
+     * @return name:county_name type:string  default:-- desc:县区名
+     * @return name:street_name type:string  default:-- desc:街道名
+     * @return name:detail type:string  default:-- desc:详细地址
+     * @return name:phone type:string  default:-- desc:联系电话
+     * @return name:name type:string   default:-- desc:联系人
+     * @return name:is_mr type:int   default:0 desc:是否是默认(0不默认,1默认)
+     */
+    public function getDeliveryAddressDetail()
+    {
+        $detail  = Db::name('delivery_address')->find(input('id'));
+        $this->success('ok',$detail);
+    }
+
+    /**
+     * @title 获取默认收货地址详情
+     * @desc  获取默认收货地址详情
+     * @author  qc
+     * @url /api/User_manage/getDefaultAddress
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:pro_id type:int   default:-- desc:省id
+     * @return name:city_id type:int   default:-- desc:市id
+     * @return name:county_id type:int  default:-- desc:县区id
+     * @return name:pro_name type:string  default:-- desc:省名
+     * @return name:city_name type:string  default:-- desc:市名
+     * @return name:county_name type:string  default:-- desc:县区名
+     * @return name:street_name type:string  default:-- desc:街道名
+     * @return name:detail type:string  default:-- desc:详细地址
+     * @return name:phone type:string  default:-- desc:联系电话
+     * @return name:name type:string   default:-- desc:联系人
+     * @return name:is_mr type:int   default:0 desc:是否是默认(0不默认,1默认)
+     */
+    public function getDefaultAddress()
+    {
+        $default  = DeliveryAddress::where(['user_id'=>$this->user_id,'is_mr'=>1])->find();
+        $detail = $default ? $default->toArray() : '';
+        $this->success('ok',$detail);
+    }
+
+    /**
+     * @title  绑定推荐人
+     * @desc  绑定推荐人
+     * @author  qc
+     * @url /api/User_manage/bindParent
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:invite_code type:string default:-- desc:推荐码
+     */
+    public function bindParent()
+    {
+        $invite_code = input('post.invite_code','');
+        $user_info = $this->userInfo();
+        if($user_info['pid']) $this->error('已绑定推荐人');
+        $invite_info = User::where(['invite_code'=>$invite_code])->find();
+        if(!$invite_info) $this->error('推荐码错误');
+        if(!$invite_info->id > $this->user_id) $this->error('无法绑定改会员为推荐人!');
+        User::update(['pid'=>$invite_info->id],['id'=>$this->user_id]);
+        InviteInfo::create(['user_id'=>$this->user_id,'pid'=>$invite_info->id,'create_at'=>date('Y-m-d H:i:s'),'type'=>2]);
+        $this->success('用户绑定成功');
+    }
+
+    /**
+     * @title  获取推荐人信息
+     * @desc  获取推荐人信息
+     * @author  qc
+     * @url /api/User_manage/getParentInfo
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:headimg type:string default:-- desc:头像
+     * @return name:create_at type:string default:-- desc:注册时间
+     */
+    public function getParentInfo()
+    {
+        $pid = User::where('id',$this->user_id)->value('pid');
+        $parent_info = [];
+        if($pid) $parent_info=  User::field('id,name,headimg,create_at')->where('id',$this->user_id)->find()->toArray();
+        $this->success('ok',$parent_info);
+    }
+
+    /**
+     * @title  通过邀请码获取用户信息(绑定推荐人可用)
+     * @desc  通过邀请码获取用户信息(绑定推荐人可用)
+     * @author  qc
+     * @url /api/User_manage/getParentInfo
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:invite_code type:string default:-- desc:邀请码
+     * @return name:name type:string default:-- desc:名称
+     * @return name:headimg type:string default:-- desc:头像
+     * @return name:create_at type:string default:-- desc:注册时间
+     */
+    public function getUserInfoByCode()
+    {
+        $invite_code = input('get.invite_code');
+        $detail = User::field('id,name,headimg')->where(['invite_code'=>$invite_code])->find();
+        if(!$detail) $this->error('没有找到用户');
+        $this->success('ok',['detail'=>$detail->toArray()]);
+
+    }
+
+
+    /**
+     * @title  获取我邀请的会员列表(我的粉丝)
+     * @desc  获取我邀请的会员列表
+     * @author  qc
+     * @url /api/User_manage/getMyInviteList
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int   default:1 desc:页数
+     * @param  name:page_num type:int   default:20 desc:每页数
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:headimg type:string default:-- desc:头像
+     * @return name:create_at type:string default:-- desc:注册时间
+     */
+    public function getMyInviteList()
+    {
+        $list =User::field('id,name,headimg,create_at')->where(['pid'=>$this->user_id])
+            ->order('id desc')
+            ->limit($this->page,$this->page_num)
+            ->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[]]);
+
+    }
+
+    /**
+     * @title 用户反馈
+     * @desc  用户反馈
+     * @author  qc
+     * @url /api/User_manage/leaveFeedback
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:phone type:string require:1 default:-- desc:电话
+     * @param name:content type:string require:1 default:-- desc:反馈内容
+     * @param name:images type:string require:0 default:-- desc:反馈图片(逗号隔开,没有不传)
+     */
+    public function leaveFeedback()
+    {
+        $insert_data = [
+            'user_id'=>$this->user_id,
+            'content'=>input('content'),
+            'phone'=>input('phone'),
+            'images'=>input('images'),
+            'create_at'=>date('Y-m-d H:i:s')
+        ];
+        Db::name('user_feedback')->insert($insert_data);
+        $this->success('反馈成功',Db::getLastInsID());
+    }
+
+
+    /**
+     * @title  获取会员等级设置
+     * @desc  获取我邀请的会员列表
+     * @author  qc
+     * @url /api/User_manage/getUserLevelSet
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:等级id
+     * @return name:name type:string default:-- desc:名称
+     * @return name:desc type:string default:-- desc:描述
+     * @return name:growth type:string default:-- desc:积分数
+     */
+    public function getUserLevelSet()
+    {
+        $list = UserLevel::field('id,name,desc,growth')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+
+
+}

+ 178 - 0
application/api/controller/UserRank.php

@@ -0,0 +1,178 @@
+<?php
+namespace app\api\controller;
+use app\common\model\RegionalAgency;
+use app\common\model\User;
+use app\common\model\UserPartner;
+use library\tools\Data;
+
+/**
+ * @title 会员区域代理&&分销
+ * @controller UserRank
+ * @group base
+ */
+class UserRank extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 申请(编辑)成为区域代理
+     * @desc  申请(编辑)成为区域代理
+     * @author  qc
+     * @url /api/User_rank/applyAgency
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:true_name type:string  default:-- desc:名称
+     * @param  name:birth type:string default:-- desc:出生日期
+     * @param  name:pro_id type:int  default:-- desc:省id
+     * @param  name:city_id type:int  default:-- desc:省id
+     * @param  name:pro_name type:string  default:-- desc:省名
+     * @param  name:city_name type:string  default:-- desc:市名
+     * @param  name:cer_type type:int  default:1 desc:证件类型(1身份证)
+     * @param  name:cer_num type:string  default:-- desc:证件号
+     * @param name:detail type:srting default:-- desc:申请详情介绍
+     */
+    public function applyAgency()
+    {
+        $true_name = input('post.true_name');
+        $birth = input('post.birth');
+        $pro_id = input('post.pro_id');
+        $city_id = input('post.city_id');
+        $pro_name = input('post.pro_name');
+        $city_name = input('post.city_name');
+        $cer_type = input('post.cer_type');
+        $cer_num = input('post.cer_num');
+        $detail = input('post.detail');
+        $is_agency = User::where('id',$this->user_id)->value('is_agency');
+        if($is_agency) $this->error('您已经是区域代理');
+        $check_apply = RegionalAgency::where(['pro_id'=>$pro_id,'city_id'=>$city_id])->find();
+        if($check_apply){
+            if($check_apply->user_id == $this->user_id && $check_apply->status == 0) $this->error('已申请,请等待审核');
+            if($check_apply->user_id == $this->user_id && $check_apply->status == 1) $this->error('您已经是该区域代理');
+            if($check_apply->user_id != $this->user_id && in_array( $check_apply->status ,[0,1])) $this->error('该区域已有代理');
+        }
+        $apply_info = [
+            'user_id' => $this->user_id ,
+            'true_name' => $true_name ,
+            'birth' => $birth,
+            'pro_id' => $pro_id ,
+            'city_id' => $city_id ,
+            'pro_name' => $pro_name ,
+            'city_name' => $city_name ,
+            'cer_type' => $cer_type ,
+            'cer_num' => $cer_num ,
+            'detail' => $detail ,
+            'create_at' => date('Y-m-d H:i:s') ,
+            'status'=> 0 ,
+        ];
+        Data::save('RegionalAgency',$apply_info,'user_id',['user_id'=>$this->user_id]);
+        $this->success('申请成功,请等待审核');
+    }
+
+    /**
+     * @title 验证区域代理
+     * @desc  验证区域代理
+     * @author  qc
+     * @url /api/User_rank/checkAgency
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:pro_id type:int  default:-- desc:省id
+     * @param  name:city_id type:int  default:-- desc:市id
+     * @return name:check_id type:int default:-- desc:大于0该市有申请记录
+     */
+    public function checkAgency()
+    {
+        $pro_id = input('get.pro_id');
+        $city_id = input('get.city_id');
+        $check_id = RegionalAgency::where(['pro_id'=>$pro_id,'city_id'=>$city_id])->where('status','<',2)->value('id');
+        $this->success('ok',['check_id'=>intval($check_id)]);
+    }
+
+    /**
+     * @title 获取我的区域申请记录
+     * @desc  获取我的区域申请记录
+     * @author  qc
+     * @url /api/User_rank/getAgencyApply
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return  name:true_name:int  default:-- desc:名称
+     * @return  name:birth:int  default:-- desc:出生日期
+     * @return  name:pro_id type:int  default:-- desc:省id
+     * @return  name:city_id type:int  default:-- desc:省id
+     * @return  name:pro_name type:string  default:-- desc:省名
+     * @return  name:city_name type:string  default:-- desc:市名
+     * @return  name:cer_type type:int  default:1 desc:证件类型(1身份证)
+     * @return  name:cer_num type:string  default:-- desc:证件号
+     * @return  name:detail type:srting default:-- desc:申请详情介绍
+     * @return  name:status type:int default:-- desc:审核状态(0未审核,1审核通过,2审核拒绝)
+     * @return  name:check_desc type:string default:-- desc:审核备注
+     */
+    public function getAgencyApply()
+    {
+        $detail = RegionalAgency::where(['user_id'=>$this->user_id])->find();
+        $this->success('ok',['list'=>$detail ? $detail->toArray() :[]]);
+    }
+
+    /**
+     * @title 申请(编辑)成为分销商
+     * @desc  申请(编辑)成为分销商
+     * @author  qc
+     * @url /api/User_rank/applyPartner
+     * @method POST
+     * @header name:Authorization require:1 desc:Token
+     * @param name:true_name:int  default:-- desc:名称
+     * @param name:cer_num type:string  default:-- desc:证件号
+     * @param name:address type:string  default:-- desc:地址
+     * @param name:phone type:string  default:-- desc:电话
+     * @param name:detail type:srting default:-- desc:申请详情介绍
+     */
+    public function applyPartner()
+    {
+        $true_name = input('post.true_name');
+        $cer_num = input('post.cer_num');
+        $address = input('post.address');
+        $detail = input('post.detail');
+        $phone = input('post.phone');
+        $partner_lev = User::where(['id'=>$this->user_id])->value('partner_lev');
+        if($partner_lev) $this->error('您已经是分销商');
+        $apply_info = [
+            'user_id' => $this->user_id ,
+            'true_name' => $true_name ,
+            'cer_num' => $cer_num ,
+            'address' => $address ,
+            'phone' => $phone ,
+            'detail' => $detail ,
+            'create_at' => date('Y-m-d H:i:s') ,
+            'status'=> 0 ,
+        ];
+        Data::save('UserPartner',$apply_info,'user_id',['user_id'=>$this->user_id]);
+        $this->success('申请成功,请等待审核');
+    }
+
+    /**
+     * @title 获取成为分销商记录申请记录
+     * @desc  获取成为分销商记录申请记录
+     * @author  qc
+     * @url /api/User_rank/getPartnerApply
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:true_name:int  default:-- desc:名称
+     * @return name:cer_num type:string  default:-- desc:证件号
+     * @return name:address type:string  default:-- desc:地址
+     * @return name:phone type:string  default:-- desc:电话
+     * @return name:detail type:srting default:-- desc:申请详情介绍
+     * @return name:status type:int default:-- desc:审核状态(0未审核,1审核通过,2审核拒绝)
+     * @return name:check_desc type:string default:-- desc:审核备注
+     */
+    public function getPartnerApply()
+    {
+        $detail = UserPartner::where(['user_id'=>$this->user_id])->find();
+        $this->success('ok',['list'=>$detail ? $detail->toArray() :[]]);
+    }
+
+
+
+}

+ 202 - 0
application/api/controller/Video.php

@@ -0,0 +1,202 @@
+<?php
+namespace app\api\controller;
+use app\common\model\GoodsOrderItem;
+use app\common\model\PlatformMessage;
+use app\common\model\StoreBanner;
+use app\common\model\UserCollect;
+use app\common\model\VideoCate;
+use app\common\model\VideoGoods;
+use app\common\model\VideoIntro;
+use library\tools\Data;
+
+/**
+ * @title 视频专栏
+ * @controller Video
+ * @group base
+ */
+class Video extends Base
+{
+
+    public function initialize()
+    {
+        parent::initialize();
+        parent::setUid();
+    }
+
+    /**
+     * @title 获取分类
+     * @desc  获取分类
+     * @author  qc
+     * @url /api/Video/getCateTree
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @return name:id type:int default:-- desc:分类id
+     * @return name:logo type:string default:-- desc:图标
+     * @return name:title type:string default:0 desc:分类名称
+     */
+    public function getCateTree()
+    {
+        $list = VideoCate::where(['is_deleted'=>0])->field('id,logo,title,pid')->order('sort desc')->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取轮播图(没有就不用)
+     * @desc  获取轮播图
+     * @author  qc
+     * @url /api/Video/getBanner
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:num type:int  default:5 desc:查询数量
+     * @return name:cover type:srting default:-- desc:图片路径
+     * @return name:link type:srting default:-- desc:链接
+     */
+    public function getBanner()
+    {
+        $num = input('get.num',5);
+        $list =  StoreBanner::where(['place'=>3,'is_deleted'=>0])
+            ->field('id,cover,link')
+            ->limit(0,$num)
+            ->order('sort desc ,id desc')
+            ->select()->toArray();
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取视频列表
+     * @desc 获取视频列表
+     * @author qc
+     * @method GET
+     * @url /api/Video/getVideoList
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:title type:string default:-- desc:标题
+     * @param  name:first_classify type:int default:0 desc:视频一级分类
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:first_classify type:int default:-- desc:视频一级分类
+     * @return name:second_classify type:int default:-- desc:视频二级分类
+     * @return name:is_top type:int default:-- desc:是否置顶(0否,1是)
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:is_collect type:int default:-- desc:是否收藏
+     */
+    public function getVideoList()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $title = input('get.title');
+        $first_classify = input('get.first_classify');
+        if($title)  $sel_where[]  = ['title','like','%'.$title.'%'];
+        if($first_classify)  $sel_where[]  = ['first_classify','=',$first_classify];
+        $list = VideoIntro::where($sel_where)
+            ->order('is_top desc,sort desc ,id desc')
+            ->limit($this->off_set,$this->page)->select()->toArray();
+        array_walk($list,function ($v,$k){
+            $v['is_collect'] = UserCollect::checkCollectByType($this->user_id,3,$v['id']);
+        });
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取最新条视频
+     * @desc 获取最新条视频
+     * @author qc
+     * @method GET
+     * @url /api/Video/getNewVideo
+     * @header name:Authorization require:1 desc:Token
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:first_classify type:int default:-- desc:视频一级分类
+     * @return name:second_classify type:int default:-- desc:视频二级分类
+     * @return name:is_top type:int default:-- desc:是否置顶(0否,1是)
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:is_collect type:int default:-- desc:是否收藏
+     */
+    public function getNewVideo()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $list = VideoIntro::where($sel_where)
+            ->order('id desc')
+            ->limit($this->off_set,$this->page_num)
+            ->select()->toArray();
+        array_walk($list,function ($v,$k){
+            $v['is_collect'] = UserCollect::checkCollectByType($this->user_id,3,$v['id']);
+        });
+        if(!empty($list) && $this->user_id){
+            $relation_id = PlatformMessage::where(['type'=>1])->max('id');// 最新的一条视频推荐
+            // 更新最新视频阅读
+            Data::save('PlatformReadLog',['user_id'=>$this->user_id,'type'=>1,'relation_id'=>$relation_id,'create_at'=>date('Y-m-d H:i:s')],'user_id',['user_id'=>$this->user_id,'type'=>1,'relation_id'=>$relation_id]);
+        }
+        $this->success('ok',['list'=>$list]);
+    }
+
+    /**
+     * @title 获取视频详情
+     * @desc 获取视频详情
+     * @author qc
+     * @method GET
+     * @url /api/Video/getVideoDetail
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:视频id
+     * @return name:title type:string default:-- desc:标题
+     * @return name:cover type:string default:-- desc:封面
+     * @return name:video_url type:string default:-- desc:视频地址
+     * @return name:first_classify type:int default:-- desc:视频一级分类
+     * @return name:is_top type:int default:-- desc:是否置顶(0否,1是)
+     * @return name:read_num type:int default:-- desc:阅读量
+     * @return name:is_collect type:int default:-- desc:是否收藏
+     */
+    public function getVideoDetail()
+    {
+        $sel_where  = [];
+        $sel_where[]  = ['is_deleted','=',0];
+        $sel_where[]  = ['status','=',1];
+        $sel_where[]  = ['id','=',input('get.id')];
+        $detail = VideoIntro::where($sel_where)
+            ->order('is_top desc,sort desc ,id desc')->find();
+        if(!$detail)$this->error('该视频已下线');
+        $detail['is_collect'] = UserCollect::checkCollectByType($this->user_id,3,$detail->id);
+        $this->success('ok',['detail'=>$detail]);
+    }
+
+    /**
+     * @title 获取视频相关商品
+     * @desc 获取视频相关商品
+     * @author qc
+     * @method GET
+     * @url /api/Video/getVideoGoods
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:id type:int default:0 desc:视频id(不传查全部的视频商品)
+     * @param  name:page type:int default:1 desc:页数
+     * @param  name:page_num type:int default:20 desc:每页数量
+     * @return name:id type:int default:-- desc:视频相关商品记录id
+     * @return name:line_price type:float default:-- desc:下划线价格
+     * @return name:video_id type:string default:-- desc:视频id
+     * @return name:goods_set type:array default:-- desc:商品信息
+     * @return name:goods_set.name type:string default:-- desc:商品名称
+     * @return name:goods_set.cover type:string default:-- desc:商品封面
+     * @return name:goods_set.low_price type:float default:-- desc:最低价格
+     */
+    public function getVideoGoods()
+    {
+        $id = input('get.id');
+        if($id){
+            $list = VideoGoods::with('goodsSet')->limit($this->off_set,$this->page_num)->select()->toArray();
+        }else{
+            $list = VideoGoods::with('goodsSet')->where(['video_id'=>$id])->limit($this->off_set,$this->page_num)->select()->toArray();
+        }
+        array_walk($list,function (&$v,$k){
+            $v['line_price'] = GoodsOrderItem::where('goods_id',$v['goods_id'])->max('original_price');
+        });
+        $this->success('ok',['list'=>$list]);
+    }
+
+
+
+
+
+}

+ 279 - 0
application/api/controller/WalletManage.php

@@ -0,0 +1,279 @@
+<?php
+
+
+namespace app\api\controller;
+use app\common\model\GoodsOrderItem;
+use app\common\model\UserBank;
+use app\common\model\UserIntegralLog;
+use app\common\model\UserLevel;
+use app\common\model\UserMoneyInfo;
+use app\common\model\UserWallet;
+use app\common\model\UserWithdrawLog;
+use think\Db;
+use app\common\model\User;
+/**
+ * @title 会员钱包管理(佣金提现,积分,经验...)
+ * @controller WalletManage
+ * @group base
+ */
+class WalletManage extends Base
+{
+    public function initialize()
+    {
+        parent::initialize();
+        parent::checkLogin();
+    }
+
+    /**
+     * @title 获取钱包详情
+     * @desc 获取钱包详情
+     * @author qc
+     * @url /api/Wallet_manage/walletInfo
+     * @method GET
+     * @tag 个人信息
+     * @header name:Authorization require:1 desc:Token
+     * @return name:detail type:array default:-- desc:钱包
+     * @return name:detail.integral type:int default:-- desc:积分
+     * @return name:detail.growth type:int default:-- desc:经验值(分销等级成长值)
+     * @return name:detail.money type:float default:-- desc:佣金
+     * @return name:detail.level_exp type:int default:-- desc:等级经验(会员等级经验值)
+     * @return name:detail.withdraw type:float default:-- desc:累积提现
+     * @return name:openid type:string default:-- desc:绑定的微信openid
+     * @return name:ali_account type:array default:-- desc:支付宝账号
+     * @return name:ali_account.real_name type:string default:-- desc:支付宝姓名
+     * @return name:ali_account.card_no type:string default:-- desc:支付宝账号
+     * @return name:bank_list type:array default:-- desc:绑定银行卡列表
+     * @return name:bank_list.real_name type:string require:1 default:-- desc:真实姓名
+     * @return name:bank_list.card_no type:string require:1 default:-- desc:账号
+     * @return name:bank_list.bank_name type:string require:1 default:-- desc:所属银行
+     *
+     */
+    public function walletInfo()
+    {
+        $wallet = UserWallet::where('user_id',$this->user_id)->find();
+        if(!$wallet) $wallet =  UserWallet::create(['user_id'=>$this->user_id]);
+        $user_info = User::field('id,name,openid,headimg')->where('id',$this->user_id)->find();
+        $ali_account = UserBank::field('id,real_name,card_no')->where(['user_id'=>$this->user_id,'type'=>1,'is_deleted'=>0])->find();
+        $bank_list = UserBank::field('id,real_name,card_no,bank_name')->where(['user_id'=>$this->user_id,'type'=>2,'is_deleted'=>0])->order('id desc')->select()->toArray();
+        $this->success('获取成功',['detail'=> $wallet->toArray(),'user_info'=>$user_info,'ali_account'=>$ali_account,'bank_list'=>$bank_list]);
+    }
+
+    /**
+     * @title 获取个人钱包信息
+     * @desc 获取个人钱包信息
+     * @author qc
+     * @url /api/Wallet_manage/getUserWallet
+     * @method GET
+     * @tag 获取个人钱包信息
+     * @header name:Authorization require:1 desc:Token
+     * @return name:phone type:int default:-- desc:手机号
+     * @return name:name type:string default:-- desc:昵称
+     * @return name:headimg type:string default:-- desc:头像地址
+     * @return name:card_front type:string default:-- desc:身份证正面
+     * @return name:card_back type:string default:-- desc:身份证背面
+     * @return name:level_name type:string default:-- desc:等级名称
+     * @return name:partner_lev type:int default:-- desc:分销商等级id(0不是分销商)
+     * @return name:is_agency type:int default:-- desc:是否是区域代理(0不是)
+     * @return name:wallet type:array default:-- desc:钱包
+     * @return name:wallet.integral type:int default:-- desc:积分
+     * @return name:wallet.growth type:int default:-- desc:经验值(分销等级成长值)
+     * @return name:wallet.money type:float default:-- desc:佣金
+     * @return name:wallet.level_exp type:int default:-- desc:经验值(会员等级)
+     *
+     */
+    public function getUserWallet()
+    {
+        $field = 'id,name,level_id,headimg,true_name,birthday,is_agency,partner_lev';
+        $user_info = User::with('wallet')->field($field)->where('id',$this->user_id)->find()->toArray();
+        $user_info['level_name'] = UserLevel::where('id',$user_info['level_id'])->value('name');
+        if(empty($user_info)) $this->error('用户信息不正确');
+        $this->success('获取成功',['user_info'=>$user_info]);
+    }
+
+
+    /**
+     * @title 佣金提现
+     * @desc 佣金提现
+     * @author qc
+     * @url /api/Wallet_manage/withdraw
+     * @method POST
+     * @tag 佣金提现
+     * @header name:Authorization require:1 desc:Token
+     * @param name:money type:float default:-- desc:提现金额
+     * @param name:type type:int default:-- desc:到账类型(1支付宝,2银行卡,3微信)
+     * @param name:pay_password type:string default:-- desc:支付密码
+     * @param name:bank_id type:int default:-- desc:账号id(type=1或2必传)
+     */
+    public function withdraw()
+    {
+       $rate        = 0.03;// 提现手续费
+       $min_money   = 100 ;// 最低提现金额
+       $max_money   = 1000;// 最大提现金额
+       $money = input('post.money',0);
+       $type = input('post.type',0);
+       $bank_id = input('post.bank_id',0);
+       $pay_password = input('post.pay_password',0);
+       if($money < $min_money) $this->error('最低提现金额:'.$min_money);
+       if($money > $max_money) $this->error('最大提现金额:'.$max_money);
+       $user_info = User::where('id',$this->user_id)->find()->toArray();
+       if(!$user_info['pay_password']) $this->error('请设置提现密码');
+       if(!check_password($pay_password,$user_info['pay_password'])) $this->error('密码错误');
+       if($type == 3 && !$user_info['openid']) $this->error('请先绑定微信!');
+       if(in_array($type,[1,2])) {
+           $acc_info = UserBank::where(['id'=>$bank_id,'user_id'=>$this->user_id])->find();
+           if(!$acc_info) $this->error('账号信息有误');
+       }
+       Db::startTrans();
+       try {
+           $wallet = UserWallet::where(['user_id'=>$this->user_id])->find();
+           if($wallet->money < $money)  $this->exception('佣金余额不足');
+           $service_fee = bcmul($money,$rate,2);
+           $account =  bcsub($money,$service_fee,2);
+           $ins_data = [
+               'user_id' => $this->user_id,
+               'money' => $money,// 提现金额
+               'rate' => $rate,// 手续费率
+               'service_fee' => $service_fee,// 手续费
+               'account' => $account,// 实际到账金额
+               'type' => $type,
+               'user_name' => $type == 3 ? $user_info['name'] : $acc_info->real_name,
+               'card_no' => $type == 3 ?  $user_info['openid'] : $acc_info->card_no,
+               'bank_name' => $type == 3 ? '微信账户' : $acc_info->bank_name,
+           ];
+           $ins_res = UserWithdrawLog::create($ins_data);// 提现日志
+           UserWallet::userMoneyChange($this->user_id,$money,'提现申请',3,-1,$ins_res->id);
+           $this->ret_msg = '申请成功';
+       }catch (\Exception $e){
+            $this->is_commit = false;
+            $this->ret_msg = $e->getMessage();
+       }
+       $this->transReturn();
+    }
+
+    /**
+     * @title 获取用户提现日志
+     * @desc 获取用户提现日志
+     * @author qc
+     * @url /api/Wallet_manage/getWithdrawLog
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:status type:int default:-1 desc:状态(0待处理,1已审核 2已到账 3已拒绝 4异常)
+     * @param  name:type type:int default:-- desc:类型
+     * @param  name:page type:int  : default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @return name:money type:float default:-- desc:提现金额
+     * @return name:type type:int default:-- desc:到账类型(1支付宝,2银行卡,3微信)
+     * @return name:money type:float default:-- desc:申请提现金额
+     * @return name:rate type:float default:-- desc:手续费率
+     * @return name:service_fee type:float default:-- desc:手续费
+     * @return name:desc type:float default:-- desc:描述
+     * @return name:status type:int default:-- desc:状态(0待处理,1已审核 2已到账 3已拒绝 4异常)
+     * @return name:user_name type:string default:-- desc:收款人
+     * @return name:card_no type:string default:-- desc:收款账号
+     * @return name:bank_name type:string default:-- desc:名称
+     */
+    public function getWithdrawLog()
+    {
+        $status = input('get.status',-1);
+        $where = [];
+        $where['is_deleted'] = 0;
+        $where['user_id'] = $this->user_id;
+        if($status) $where['status'] =  $status;
+        $list = UserWithdrawLog::where($where)->limit($this->off_set,$this->page_num)
+            ->order('id desc')->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[]]);
+    }
+
+    /**
+     * @title 获取用户佣金变更记录
+     * @desc 获取用户佣金变更记录
+     * @author qc
+     * @url /api/Wallet_manage/getUserMoneyInfo
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  : default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @return name:money type:float default:-- desc:金额
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:desc type:float default:-- desc:描述
+     */
+    public function getUserMoneyInfo()
+    {
+        $where = [];
+        $where['user_id'] = $this->user_id;
+        $list = UserMoneyInfo::where($where)->limit($this->off_set,$this->page_num)->order('id desc')->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[]]);
+    }
+
+    /**
+     * @title 获取用户积分变更记录
+     * @desc 获取用户积分变更记录
+     * @author qc
+     * @url /api/Wallet_manage/getUserIntegralLog
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  : default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @param  name:type type:int  : default:0 desc:类型(0全部,1增加,2减少)
+     * @return name:integral type:int default:-- desc:变更数量
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:desc type:float default:-- desc:描述
+     */
+    public function getUserIntegralLog()
+    {
+        $where = [];
+        $where[] = ['user_id','=',$this->user_id];
+        $where[] = ['is_deleted','=',0];
+        if(input('type') == 1) $where[] = ['integral','>','0'];
+        if(input('type') == 2) $where[] = ['integral','<','0'];
+        $list = UserIntegralLog::where($where)->limit($this->off_set,$this->page_num)->order('id desc')->select();
+        $this->success('ok',['list'=>$list ? $list->toArray():[]]);
+    }
+
+
+    /**
+     * @title 获取用户分销佣金记录
+     * @desc 获取用户分销佣金记录
+     * @author qc
+     * @url /api/Wallet_manage/getDistributionMoney
+     * @method GET
+     * @header name:Authorization require:1 desc:Token
+     * @param  name:page type:int  : default:1 desc:页数
+     * @param  name:page_num type:int  : default:20 desc:每页数
+     * @return name:money type:float default:-- desc:金额
+     * @return name:create_at type:string default:-- desc:时间
+     * @return name:desc type:float default:-- desc:描述
+     * @return name:type type:float default:-- desc:类型(7一级分销,8二级分销)
+     * @return name:user_info type:array default:-- desc:会员信息
+     * @return name:user_info.name type:string default:-- desc:会员名
+     * @return name:user_info.headimg type:string default:-- desc:会员头像
+     * @return name:goods_list type:array default:-- desc:商品列表
+     * @return name:goods_list.cover type:array default:-- desc:商品图
+     * @return name:goods_list.goods_name type:string default:-- desc:商品名
+     * @return name:goods_list.goods_spec type:string default:-- desc:商品规格
+     * @return name:goods_list.sell_money type:float default:-- desc:商品价格
+     * @return name:goods_list.is_dist type:int default:-- desc:是否是分销商品(0否,1是)
+     */
+    public function getDistributionMoney()
+    {
+        $where = [];
+        $where[] = ['user_id','=',$this->user_id];
+        $where[] = ['type','in','7,8'];
+        $list = UserMoneyInfo::where($where)->limit($this->off_set,$this->page_num)->order('id desc')->select();
+        array_walk($list,function ($val){
+            $val['user_info']  = User::where('id',$val['user_id'])->field('id,name,headimg')->find()->toArray();
+            $goods_list = GoodsOrderItem::where('i.order_id',$val['id'])
+                ->alias('i')
+                ->leftJoin('StoreGoods g','g.id = i.goods_id')
+                ->field('i.cover,i.sell_money,i.num,g.is_dist,i.goods_name,i.goods_spec')
+                ->select()->toArray();
+            $val['goods_list'] = $goods_list;
+        });
+        $this->success('ok',['list'=>$list ? $list->toArray():'']);
+    }
+
+
+
+
+
+}

+ 166 - 0
application/api/controller/WeChatPay.php

@@ -0,0 +1,166 @@
+<?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\api\controller;
+use app\common\model\GiftOrder;
+use app\common\model\GoodsOrder;
+use app\common\model\ExchangeOrder;
+use app\common\service\OrderCallback;
+use EasyWeChat\Factory;
+use think\Controller;
+use think\Db;
+use think\Exception;
+use app\api\controller\Evaluate;
+use AlibabaCloud\Client\AlibabaCloud;
+use AlibabaCloud\Client\Exception\ClientException;
+use AlibabaCloud\Client\Exception\ServerException;
+/**
+ * 微信支付管理类
+ * Class WeChatPay
+ * @package app\api\controller\WeChatPay
+ */
+class WeChatPay extends Controller
+{
+    //小程序微信支付(type为1时是货主端微信配置,type为2时是接单端微信配置)
+    public static function wxPay($name='订单支付',$out_trade_no,$total_fee,$notify_url,$trade_type = 'JSAPI',$openid = ''){
+        try{
+            if(empty($out_trade_no) || empty($total_fee) || empty($notify_url)) return false;
+            $parameter = [
+                'body'          => $name,
+                'out_trade_no'  => $out_trade_no,
+                'total_fee'     => $total_fee*100,
+                'notify_url'    => $notify_url, // 支付结果通知网址,如果不设置则会使用配置里的默认地址
+                'trade_type'    => $trade_type, // 请对应换成你的支付方式对应的值类型
+            ];
+            switch ($trade_type){
+                case 'JSAPI':
+                    $app = Factory::payment(config('app.wx_pay'));
+                    break;
+                case 'NATIVE':
+                    $app = Factory::payment(config('app.wx_pay'));
+                    break;
+                case 'APP':
+                    $app = Factory::payment(config('app.app_wx'));
+                    break;
+            }
+            if($trade_type != 'APP') $parameter['openid'] = $openid;
+            $result = $app->order->unify($parameter);
+            $jssdk = $app->jssdk;
+            if($trade_type == 'APP') {
+                $config = $jssdk->appConfig($result['prepay_id']);
+            }else{
+                $config = $jssdk->sdkConfig($result['prepay_id']);
+            }
+            return ['code'=> $config ? 200 : 201 , 'config'=>$config,'msg'=>'ok'];
+        }catch (\Exception $e){
+            return ['code'=> 201,'config'=>[],'msg'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * 商城订单支付回调
+     */
+    public function goodsOrderNotify()
+    {
+        $app = Factory::payment(config('app.wx_pay'));
+        $response = $app->handlePaidNotify(function ($message, $fail) {
+            $this->payResultLog($message,'dd_goods_order');
+            // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
+            $pay_no = $message['out_trade_no'];
+            // 如果订单不存在 或者 订单已经支付过了  告诉微信,我已经处理完了,订单没找到,别再通知我了
+            if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
+                $order_info = GoodsOrder::with('orderItem')->where('pay_no',$pay_no)->find();
+                if(!$order_info) return false;
+                $order_info = $order_info->toArray();
+                if($order_info['status'] != 0) return true;
+                $back_res = OrderCallback::goodsOrderCallBack($order_info,1);// 支付完成后回调
+                return $back_res['ret_val'];
+            } else if ($message['return_code'] != 'SUCCESS'){
+                return $fail('通信失败,请稍后再通知我');
+            }
+        });
+        $response->send();
+    }
+
+    /**
+     * 礼品定制订单回调
+     */
+    public function customOrderNotify()
+    {
+        $app = Factory::payment(config('app.wx_pay'));
+        $response = $app->handlePaidNotify(function ($message, $fail) {
+            $this->payResultLog($message,'dd_gift_order');
+            // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
+            $pay_no = $message['out_trade_no'];
+            // 如果订单不存在 或者 订单已经支付过了  告诉微信,我已经处理完了,订单没找到,别再通知我了
+            if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
+                $order_info = GiftOrder::where('pay_no',$pay_no)->find();
+                if(!$order_info) return false;
+                $order_info = $order_info->toArray();
+                if($order_info['status'] != 0) return true;
+                $back_res = OrderCallback::customOrderCallBack($order_info,1);// 支付完成后回调
+                return $back_res['ret_val'];
+            } else if ($message['return_code'] != 'SUCCESS'){
+                return $fail('通信失败,请稍后再通知我');
+            }
+        });
+        $response->send();
+    }
+
+    /**
+     * 兑换商品订单支付回调
+     */
+    public function exchangeOrderNotify()
+    {
+        $app = Factory::payment(config('app.wx_pay'));
+        $response = $app->handlePaidNotify(function ($message, $fail) {
+            $this->payResultLog($message,'dd_exchange_order');
+            // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
+            $pay_no = $message['out_trade_no'];
+            // 如果订单不存在 或者 订单已经支付过了  告诉微信,我已经处理完了,订单没找到,别再通知我了
+            if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
+                $order_info = ExchangeOrder::where('pay_no',$pay_no)->find();
+                if(!$order_info) return false;
+                $order_info = $order_info->toArray();
+                if($order_info['status'] != 0) return true;
+                return OrderCallback::exchangeOrderCallBack($order_info,1);
+            } else if ($message['return_code'] != 'SUCCESS'){
+                return $fail('通信失败,请稍后再通知我');
+            }
+        });
+        $response->send();
+    }
+
+    /**
+     * 记录支付日志
+     * @param $message
+     * @param $table_name
+     */
+    public function payResultLog($message,$table_name)
+    {
+        // 回调记录
+        $ret_arr = [];
+        $ret_arr['transaction_id'] =    isset($message['transaction_id']) ?$message['transaction_id']: '';
+        $ret_arr['trade_no'] =          isset($message['out_trade_no']) ?$message['out_trade_no']: '';
+        $ret_arr['return_code'] =       isset($message['return_code']) ?$message['return_code']: '';
+        $ret_arr['result_code'] =       isset($message['result_code']) ?$message['result_code']: '';
+        $ret_arr['create_at'] =         date('Y-m-d H:i:s');
+        $ret_arr['order_table'] =       $table_name;
+        $ret_arr['result'] =            json_encode($message);
+        Db::name('order_pay_result')->insert($ret_arr);
+    }
+
+
+}

+ 26 - 0
application/api/controller/WeChatPort.php

@@ -0,0 +1,26 @@
+<?php
+namespace app\api\controller;
+use EasyWeChat\Factory;
+use EasyWeChat\MiniProgram\Application;
+use think\Controller;
+
+/**
+ * 微信接口
+ * Class WeChatPort
+ * @package app\api\controller\WeChatPay
+ */
+class WeChatPort extends Controller
+{
+    // 获取微信小程序AccessToken
+    public static function getAccessToken($code)
+    {
+        $res = http_curl('https://api.weixin.qq.com/cgi-bin/token?appid='.config('mini_program')['app_id'].'&secret='.config('mini_program')['secret'].'&code='.$code.'&grant_type=client_credential');
+        return $res;
+    }
+
+    public  static function getUserInfo($code)
+    {
+
+    }
+
+}

+ 275 - 0
application/common.php

@@ -0,0 +1,275 @@
+<?php
+use think\Db;
+/**
+ * 秒转换为天
+ */
+function get_stay_time($remain_time, $is_hour = 1, $is_minutes = 1)
+{
+    $day = floor($remain_time / (3600*24));
+    $day = $day > 0 ? $day.'天' : '';
+    $hour = floor(($remain_time % (3600*24)) / 3600);
+    $hour = $hour > 0 ? $hour.'小时' : '';
+    if($is_hour && $is_minutes) {
+        $minutes = floor((($remain_time % (3600*24)) % 3600) / 60);
+        $minutes = $minutes > 0 ? $minutes.'分钟' : '';
+        return $day.$hour.$minutes;
+    }
+
+    if($hour) {
+        return $day.$hour;
+    }
+    return $day;
+}
+//获取全图片地址 $image_data
+function image_path($image_data){
+    if(empty($image_data)){
+        return $image_data;
+    }
+    if (strpos($image_data,'|')!==false){
+        $image_res = explode('|',$image_data);
+    }elseif(strpos($image_data,',')!==false){
+        $image_res = explode(',',$image_data);
+    }else{
+        $image_res = array($image_data);
+    }
+    return $image_res;
+}
+
+/**
+ * @param $id_card
+ * @return false|string
+ */
+function get_age($id_card){
+    # 1.从身份证中获取出生日期
+    $birth_Date = strtotime(substr($id_card, 6, 8));//截取日期并转为时间戳
+
+    # 2.格式化[出生日期]
+    $Year = date('Y', $birth_Date);//yyyy
+    $Month = date('m', $birth_Date);//mm
+    $Day = date('d', $birth_Date);//dd
+
+    # 3.格式化[当前日期]
+    $current_Y = date('Y');//yyyy
+    $current_M = date('m');//mm
+    $current_D = date('d');//dd
+
+    # 4.计算年龄()
+    $age = $current_Y - $Year;//今年减去生日年
+    if($Month > $current_M || $Month == $current_M && $Day > $current_D){//深层判断(日)
+        $age--;//如果出生月大于当前月或出生月等于当前月但出生日大于当前日则减一岁
+    }
+    # 返回
+    return $age;
+
+}
+
+function create_invite_code($user_id){
+    // 生成12位邀请码
+    $code_str = '';
+    $base_code = explode(',',"A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z");
+    $code_key = array_rand($base_code, 10 - strlen($user_id));
+    array_map(function ($val)use (&$code_str,$base_code){
+        $code_str .=$base_code[$val] ;
+    },$code_key);
+    return $code_str.$user_id;
+}
+
+// 获取模板区域
+function get_city_area()
+{
+    $field=['id','pid','name'];
+    $list=Db::name('china_area')->where('pid',0)->field($field)->select();
+    foreach ($list as $k=>&$v){
+        $v['children']= Db::name('china_area')->where('pid',$v['id'])->field($field)->select();
+    }
+    return $list;
+}
+
+function http_curl($url,$type='get',$res='json',$arr=''){
+
+    $headers = array();
+    //根据API的要求,定义相对应的Content-Type
+    array_push($headers, "Content-Type".":"."application/x-www-form-urlencoded; charset=UTF-8;application/json");
+    $curl = curl_init();
+    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $type);
+    curl_setopt($curl, CURLOPT_URL, $url);
+    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+    curl_setopt($curl, CURLOPT_FAILONERROR, false);
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($curl, CURLOPT_HEADER, false);
+    $output = curl_exec($curl);
+    curl_close($curl);
+    if($res=='json'){
+        if($output === false){
+            //请求失败,返回错误信息
+            return curl_error($curl);
+        }else{
+            //请求成功,返回信息
+            return json_decode($output,true);
+        }
+    }
+}
+
+function curl_get($url)
+{
+    $ch = curl_init();
+    curl_setopt($ch, CURLOPT_URL, $url);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    $output = curl_exec($ch);
+    curl_close($ch);
+    if($output === false){
+        return curl_error($ch);
+    }else{
+        return json_decode($output,true);
+    }
+}
+
+// 获取物流信息
+function get_delivery($send_no = 'JD0053309649641',$express_code=''){
+        error_reporting(E_ALL || ~E_NOTICE);
+        $AppKey     = 204008273;
+        $AppSecret  ='t9PavvfCeK5v2XidwyK5pWDp8b0hzMq4';
+        $AppCode    ='47f640e3529d43e28365311a530db2b7';//开通服务后 买家中心-查看AppCode
+        $host = "https://wuliu.market.alicloudapi.com";//api访问链接
+        $path = "/kdi";//API访问后缀
+        $method = "GET";
+        $body  ='';
+        $headers = array();
+        array_push($headers, "Authorization:APPCODE " . $AppCode);
+        $querys = "no={$send_no}&type={$express_code}";  //参数写在这里
+        $url = $host . $path . "?" . $querys;
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
+        curl_setopt($curl, CURLOPT_URL, $url);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($curl, CURLOPT_FAILONERROR, false);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($curl, CURLOPT_HEADER, true);
+        if (1 == strpos("$" . $host, "https://")) {
+            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+        }
+        $out_put = curl_exec($curl);
+        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+        list($header, $body) = explode("\r\n\r\n", $out_put, 2);
+        if ($httpCode == 200) {
+            return json_decode($body,true)['result'];
+        } else {
+            return [];
+        }
+    }
+
+// 实名认证
+function user_certification($id_card,$name){
+    $host = "http://checkone.market.alicloudapi.com";
+    $path = "/chinadatapay/1882";
+    $method = "POST";
+    $appcode = "30be8bdcc65842919980a8276ffc4995";
+    $headers = array();
+    array_push($headers, "Authorization:APPCODE " . $appcode);
+    //根据API的要求,定义相对应的Content-Type
+    array_push($headers, "Content-Type".":"."application/x-www-form-urlencoded; charset=UTF-8");
+
+    $bodys = "idcard=".$id_card."&name=".$name;
+    $url = $host . $path;
+
+    $curl = curl_init();
+    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
+    curl_setopt($curl, CURLOPT_URL, $url);
+    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+    curl_setopt($curl, CURLOPT_FAILONERROR, false);
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($curl, CURLOPT_HEADER, false);
+    if (1 == strpos("$".$host, "https://"))
+    {
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+    }
+    curl_setopt($curl, CURLOPT_POSTFIELDS, $bodys);
+    $res = curl_exec($curl);
+    if($res){
+        $res = json_decode($res,true);
+        if($res['data']['result'] == 1){
+           return 1;
+        }else{
+            return 0;
+        }
+    }else{
+       return 0;
+    }
+}
+
+/**
+ * 把返回的数据集转换成Tree
+ * @param array $list 要转换的数据集
+ * @param string $pk 自增字段(栏目id)
+ * @param string $pid parent标记字段
+ * @return array
+ */
+function make_tree($list,$pk='id',$pid='pid',$child='children',$root=0){
+    if(is_object($list)) $list = $list->toArray();
+    $tree=array();
+    $packData=array();
+    foreach ($list as $data) {
+        $packData[$data[$pk]] = $data;
+    }
+    foreach ($packData as $key =>$val){
+       if($val[$pid]==$root){//代表跟节点
+            $tree[]=& $packData[$key];
+        }else{
+            $packData[$val[$pid]][$child][]=& $packData[$key]; //找到其父类
+        }
+    }
+    return $tree;
+}
+
+
+//判断字段存在并不为空
+function isset_full($arr, $key)
+{
+    if (isset($arr[$key]) && !empty($arr[$key])) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+//判断字段存在并不为空 并且等于验证值
+function isset_full_check($arr, $key,$check_val)
+{
+    if (isset($arr[$key]) && !empty($arr[$key]) && $arr[$key] == $check_val) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+function all_pay_type()
+{
+    return [ '--','微信[小程序]','余额','支付宝[APP]','微信[APP]','微信[扫码]','支付宝[扫码]' ];
+}
+
+/**
+ * @param $start 验证开始时间
+ * @param $end   验证结束时间
+ * @param $check_st  已有活动开始时间
+ * @param $check_end 已有活动结束时间
+ * @return bool  true 可以创建活动
+ */
+function check_act_time($start,$end,$check_st,$check_end)
+{
+    $check_val = false;
+    if($start > $check_end || $end < $check_st) $check_val = true;
+    return  $check_val;
+}
+
+
+
+
+
+
+
+
+
+

+ 8 - 0
application/common/model/BaseGoods.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 商品
+class BaseGoods extends Model
+{
+
+}

+ 10 - 0
application/common/model/BaseGoodsItem.php

@@ -0,0 +1,10 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 商品规格
+class BaseGoodsItem extends Model
+{
+
+
+
+}

+ 16 - 0
application/common/model/ChinaArea.php

@@ -0,0 +1,16 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 地址管理
+class ChinaArea extends Model
+{
+    public static function getAllCity()
+    {
+        $all_first = self::field('first')->order('first asc')->group('first')->select()->toArray();
+        array_walk($all_first,function (&$v,$k){
+            $v['city_list'] = self::field('id,name,short_name')->where(['first'=>$v['first'],'level'=>2])->select()->toArray();
+        });
+        return  $all_first;
+    }
+
+}

+ 9 - 0
application/common/model/CouponConfig.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 优惠券
+class CouponConfig extends Model
+{
+
+
+}

+ 8 - 0
application/common/model/DeliveryAddress.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 收货地址
+class DeliveryAddress extends Model
+{
+
+}

+ 9 - 0
application/common/model/Depot.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\common\model;
+use library\tools\Data;
+use think\Model;
+// 仓库
+class Depot extends Model
+{
+
+}

+ 28 - 0
application/common/model/DepotGoods.php

@@ -0,0 +1,28 @@
+<?php
+namespace app\common\model;
+use library\tools\Data;
+use think\Model;
+// 仓库商品
+class DepotGoods extends Model
+{
+    // 验证仓库是否有该商品。。没有则添加到仓库
+    public static function checkDepotGoods($goods_id,$depot_id)
+    {
+        $check_goods =  self::where(['goods_id'=>$goods_id,'depot_id'=>$depot_id])->count();
+        if($check_goods) return true;
+        $int_data=[
+            'depot_id' => $depot_id,
+            'goods_id' => $goods_id,
+            'sort' => 0,
+            'create_at' => date("Y-m-d H:i:s")
+        ];
+        self::create($int_data);
+        $goods_item = StoreGoodsItem::where('goods_id',$goods_id)->field("goods_id,id as spec_id,goods_spec")->select()->toArray();
+        array_walk($goods_item,function (&$v,$k)use($depot_id,$goods_id){
+            $v['depot_id'] = $depot_id;
+            Data::save('DepotGoodsItem',$v,'depot_id',['depot_id'=>$depot_id,'goods_id'=>$goods_id,'spec_id'=>$v['spec_id']]);
+        });
+    }
+
+
+}

+ 8 - 0
application/common/model/DepotGoodsItem.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 仓库商品规格设置
+class DepotGoodsItem extends Model
+{
+
+}

+ 8 - 0
application/common/model/DiscountActivity.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 折扣活动
+class DiscountActivity extends Model
+{
+
+}

+ 8 - 0
application/common/model/DiscountGoods.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 折扣活动商品
+class DiscountGoods extends Model
+{
+
+}

+ 8 - 0
application/common/model/ExchangeGoods.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 兑换商品
+class ExchangeGoods extends Model
+{
+
+}

+ 8 - 0
application/common/model/ExchangeOrder.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 兑换商品订单
+class ExchangeOrder extends Model
+{
+
+}

+ 8 - 0
application/common/model/GiftCate.php

@@ -0,0 +1,8 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 心选礼物分类
+class GiftCate extends Model
+{
+
+}

+ 12 - 0
application/common/model/GiftGoods.php

@@ -0,0 +1,12 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 心选礼物
+class GiftGoods extends Model
+{
+    public function itemList()
+    {
+        return $this->hasMany('StoreGoodsItem','goods_id','goods_id')->field('id,goods_id,goods_spec,stock,stock,weight');
+    }
+
+}

+ 12 - 0
application/common/model/GiftOrder.php

@@ -0,0 +1,12 @@
+<?php
+namespace app\common\model;
+use think\Model;
+// 心选礼物定制订单
+class GiftOrder extends Model
+{
+    public function goods()
+    {
+        return $this->belongsTo('StoreGoods','goods_id')->field('id,name,cover');
+    }
+
+}

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