Browse Source

首次提交

liuxiangxin 7 months ago
parent
commit
2f498c1161
100 changed files with 10377 additions and 0 deletions
  1. 5 0
      .gitattributes
  2. 18 0
      .gitignore
  3. 13 0
      .styleci.yml
  4. 106 0
      app/Console/Commands/StaffRelation.php
  5. 107 0
      app/Console/Commands/StaffRemark.php
  6. 108 0
      app/Console/Commands/TagRelation.php
  7. 204 0
      app/Console/Commands/WorkSync.php
  8. 47 0
      app/Console/Kernel.php
  9. 48 0
      app/Exceptions/Admin/AuthException.php
  10. 64 0
      app/Exceptions/Api/ApiException.php
  11. 11 0
      app/Exceptions/Api/LoginException.php
  12. 15 0
      app/Exceptions/Api/ValidException.php
  13. 15 0
      app/Exceptions/Api/VerifySignException.php
  14. 90 0
      app/Exceptions/Handler.php
  15. 24 0
      app/Facades/Servers/Encrypts/AccessToken.php
  16. 26 0
      app/Facades/Servers/Encrypts/ApiSign.php
  17. 24 0
      app/Facades/Servers/Encrypts/Simple.php
  18. 29 0
      app/Facades/Servers/Logs/Log.php
  19. 33 0
      app/Facades/Servers/Redis/Redis.php
  20. 23 0
      app/Facades/Servers/Redis/RedisLock.php
  21. 28 0
      app/Facades/Servers/Tencent/Cos.php
  22. 24 0
      app/Facades/Servers/Tencent/Sms.php
  23. 30 0
      app/Facades/Servers/WechatMini/Mini.php
  24. 30 0
      app/Facades/Servers/WechatWork/ContactWay.php
  25. 34 0
      app/Facades/Servers/WechatWork/CorpTag.php
  26. 30 0
      app/Facades/Servers/WechatWork/Department.php
  27. 30 0
      app/Facades/Servers/WechatWork/ExternalContact.php
  28. 28 0
      app/Facades/Servers/WechatWork/User.php
  29. 29 0
      app/Facades/Servers/WeiBan/OpenApi.php
  30. 370 0
      app/Helpers/functions.php
  31. 40 0
      app/Http/Controllers/Admin/Admin.php
  32. 63 0
      app/Http/Controllers/Admin/AdminHistory.php
  33. 255 0
      app/Http/Controllers/Admin/AdminUser.php
  34. 73 0
      app/Http/Controllers/Admin/Auth.php
  35. 201 0
      app/Http/Controllers/Admin/AuthManager.php
  36. 144 0
      app/Http/Controllers/Admin/Banner.php
  37. 145 0
      app/Http/Controllers/Admin/Business.php
  38. 66 0
      app/Http/Controllers/Admin/Config.php
  39. 205 0
      app/Http/Controllers/Admin/ContactWay.php
  40. 181 0
      app/Http/Controllers/Admin/CorpTag.php
  41. 420 0
      app/Http/Controllers/Admin/Coupon.php
  42. 152 0
      app/Http/Controllers/Admin/Custom.php
  43. 154 0
      app/Http/Controllers/Admin/CustomCompany.php
  44. 104 0
      app/Http/Controllers/Admin/CustomScore.php
  45. 32 0
      app/Http/Controllers/Admin/FilesManager.php
  46. 317 0
      app/Http/Controllers/Admin/ImageManager.php
  47. 48 0
      app/Http/Controllers/Admin/Index.php
  48. 94 0
      app/Http/Controllers/Admin/Login.php
  49. 96 0
      app/Http/Controllers/Admin/Menu.php
  50. 395 0
      app/Http/Controllers/Admin/Orders.php
  51. 129 0
      app/Http/Controllers/Admin/OrdersBanner.php
  52. 101 0
      app/Http/Controllers/Admin/OrdersProduct.php
  53. 154 0
      app/Http/Controllers/Admin/OrdersTransport.php
  54. 528 0
      app/Http/Controllers/Admin/Product.php
  55. 155 0
      app/Http/Controllers/Admin/ProductSpec.php
  56. 131 0
      app/Http/Controllers/Admin/ProductType.php
  57. 111 0
      app/Http/Controllers/Admin/ScoreClockin.php
  58. 96 0
      app/Http/Controllers/Admin/ScoreOrders.php
  59. 159 0
      app/Http/Controllers/Admin/ScoreProduct.php
  60. 186 0
      app/Http/Controllers/Admin/Stock.php
  61. 222 0
      app/Http/Controllers/Admin/Ueditor.php
  62. 64 0
      app/Http/Controllers/Admin/WeibanExternal.php
  63. 127 0
      app/Http/Controllers/Admin/WeibanQrcode.php
  64. 246 0
      app/Http/Controllers/Admin/WorkSync.php
  65. 168 0
      app/Http/Controllers/Api/Api.php
  66. 50 0
      app/Http/Controllers/Api/Banner.php
  67. 81 0
      app/Http/Controllers/Api/Custom.php
  68. 158 0
      app/Http/Controllers/Api/CustomAddr.php
  69. 87 0
      app/Http/Controllers/Api/CustomCompany.php
  70. 142 0
      app/Http/Controllers/Api/CustomCoupon.php
  71. 72 0
      app/Http/Controllers/Api/CustomScore.php
  72. 282 0
      app/Http/Controllers/Api/Orders.php
  73. 34 0
      app/Http/Controllers/Api/Orders/Banner.php
  74. 161 0
      app/Http/Controllers/Api/Product.php
  75. 60 0
      app/Http/Controllers/Api/Score/Clockin.php
  76. 166 0
      app/Http/Controllers/Api/Score/Orders.php
  77. 87 0
      app/Http/Controllers/Api/Score/Product.php
  78. 215 0
      app/Http/Controllers/Api/ShopCart.php
  79. 22 0
      app/Http/Controllers/Api/Test.php
  80. 53 0
      app/Http/Controllers/Api/Wechat.php
  81. 192 0
      app/Http/Controllers/Api/WechatWork.php
  82. 37 0
      app/Http/Controllers/Api/WeiZan/Orders.php
  83. 85 0
      app/Http/Controllers/Api/WorkBind.php
  84. 168 0
      app/Http/Controllers/Controller.php
  85. 78 0
      app/Http/Kernel.php
  86. 204 0
      app/Http/Middleware/AdminAuth.php
  87. 21 0
      app/Http/Middleware/Authenticate.php
  88. 22 0
      app/Http/Middleware/EncryptCookies.php
  89. 68 0
      app/Http/Middleware/LoadLocale.php
  90. 17 0
      app/Http/Middleware/PreventRequestsDuringMaintenance.php
  91. 32 0
      app/Http/Middleware/RedirectIfAuthenticated.php
  92. 23 0
      app/Http/Middleware/TrimStrings.php
  93. 20 0
      app/Http/Middleware/TrustHosts.php
  94. 24 0
      app/Http/Middleware/TrustProxies.php
  95. 35 0
      app/Http/Middleware/VerifyCsrfToken.php
  96. 72 0
      app/Http/Requests/Admin/AdminUser.php
  97. 56 0
      app/Http/Requests/Admin/AuthManager.php
  98. 49 0
      app/Http/Requests/Admin/Banner.php
  99. 56 0
      app/Http/Requests/Admin/Business.php
  100. 43 0
      app/Http/Requests/Admin/Config.php

+ 5 - 0
.gitattributes

@@ -0,0 +1,5 @@
+* text=auto
+*.css linguist-vendored
+*.scss linguist-vendored
+*.js linguist-vendored
+CHANGELOG.md export-ignore

+ 18 - 0
.gitignore

@@ -0,0 +1,18 @@
+/.idea
+/.vscode
+/.well-known
+/bootstrap/cache/*
+/storage/framework/cache/*
+/storage/framework/sessions/*
+/storage/framework/testing/*
+/storage/framework/views/*
+/elkconf
+/vendor
+*.DS_Store
+*.log
+.env
+.env.backup
+.phpunit.result.cache
+docker-compose.override.yml
+Homestead.json
+Homestead.yaml

+ 13 - 0
.styleci.yml

@@ -0,0 +1,13 @@
+php:
+  preset: laravel
+  disabled:
+    - no_unused_imports
+  finder:
+    not-name:
+      - index.php
+      - server.php
+js:
+  finder:
+    not-name:
+      - webpack.mix.js
+css: true

+ 106 - 0
app/Console/Commands/StaffRelation.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Facades\Servers\WeiBan\OpenApi;
+use App\Models\WeiBan\Sync as Model;
+use App\Jobs\WeiBanSync as WeiBanSyncJobs;
+use App\Facades\Servers\Logs\Log;
+
+class StaffRelation extends Command
+{
+    /**
+     * 任务名称
+     *
+     * @var string
+     */
+    protected $signature = 'staff_relation';
+
+    /**
+     * 任务描述
+     *
+     * @var string
+     */
+    protected $description = '微伴客户关系同步任务';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+      try {
+        // 数据结果
+        $this->sync_user(new Model());
+        return 0;
+      } catch (\Throwable $th) {
+        // 记录错误信息
+        Log::error('staff_relation',$th->getMessage());
+        return 0;
+      }
+    }
+
+	
+    /**
+     * 客户关系同步
+     * 
+     * */
+    public function sync_user(Model $Model)
+    {
+      // 更新维度
+      $source             = 'staff_relation';
+      // 同步关系的任务
+      $task				        = $Model->getOneBySource($source);
+      // 返回结果
+      if( !$task['id'] )	return ['error'=>'无执行任务'];
+      // 获取列表
+      $userList           = OpenApi::getUserList($task['limit'],$task['offset'],$task['last_time']);
+      // 最后的更新时间
+      $lastTime           = 0;
+      // 放到队列执行
+      foreach ($userList['user_list'] as $key=>$value) {
+          // 获取最后更新时间
+          $lastTime       = $value['updated_at'];
+          // 外部联系人
+          $value          = ['id'=>$value['id']];
+          // 发送到队列执行,上锁成功则发送到队列执行
+          if( $Model->lockSyncExtidMark($value['id']) )  WeiBanSyncJobs::dispatch($value);
+          // 重组下数据
+          $userList['user_list'][$key]  = $value;
+      }
+      // 存在用户列表的话,更新OR新增
+      if( $userList['user_list'] ) {
+        // 更新下一页偏移量
+        $task['offset']     = $task['offset'] + $task['limit'];
+        // 同步数量
+        $task['sync_total'] = $task['sync_total'] + count($userList['user_list']);
+      }
+      // 更新任务总数
+      if( $userList['total'] ) {
+          // 更新任务总数
+          $task['total']                  = $userList['total'];
+          // 偏移量大于总数,更新任务状态
+          if( $task['offset']             >= $userList['total'] ) {
+              // 状态结束
+              $task['status']             = 1;
+              // 最后的修改时间
+              $task['last_time']          = $lastTime - 1;
+          }
+      }
+      // 修改任务情况
+      $Model->edit($task['id'],$task);
+    }
+
+}

+ 107 - 0
app/Console/Commands/StaffRemark.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Facades\Servers\WeiBan\OpenApi;
+use App\Models\WeiBan\Sync as Model;
+use App\Jobs\WeiBanSync as WeiBanSyncJobs;
+use App\Facades\Servers\Logs\Log;
+
+class StaffRemark extends Command
+{
+    /**
+     * 任务名称
+     *
+     * @var string
+     */
+    protected $signature = 'staff_remark';
+
+    /**
+     * 任务描述
+     *
+     * @var string
+     */
+    protected $description = '微伴画像数据同步任务';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+      try {
+        // 数据结果
+        $this->sync_user(new Model());
+        return 0;
+      } catch (\Throwable $th) {
+        // 记录错误信息
+        Log::error('staff_remark',$th->getMessage());
+        return 0;
+      }
+    }
+
+	
+    /**
+     * 客户关系同步
+     * 
+     * */
+    public function sync_user(Model $Model)
+    {
+      // 更新维度
+      $source             = 'remark';
+      // 同步关系的任务
+      $task				        = $Model->getOneBySource($source);
+      // 返回结果
+      if( !$task['id'] )	return ['error'=>'无执行任务'];
+      // 获取列表
+      $userList           = OpenApi::getUserList($task['limit'],$task['offset'],$task['last_time']);
+      // 最后的更新时间
+      $lastTime           = 0;
+      // 放到队列执行
+      foreach ($userList['user_list'] as $key=>$value) {
+          // 获取最后更新时间
+          $lastTime       = $value['updated_at'];
+          // 外部联系人
+          $value          = ['id'=>$value['id']];
+          // ['id'=>$value['id'],'name'=>$value['name'],'avatar'=>str_ireplace('http://','https://',(string)$value['avatar']),'gender'=>$value['gender'],'type'=>$value['type'],'corp_name'=>(string)$value['corp_name'],'corp_full_name'=>(string)$value['corp_full_name'],'insert_time'=>$value['created_at'],'update_time'=>$value['updated_at'],];
+          // 发送到队列执行,上锁成功则发送到队列执行
+          if( $Model->lockSyncExtidMark($value['id']) )  WeiBanSyncJobs::dispatch($value);
+          // 重组下数据
+          $userList['user_list'][$key]  = $value;
+      }
+      // 存在用户列表的话,更新OR新增
+      if( $userList['user_list'] ) {
+        // 更新下一页偏移量
+        $task['offset']     = $task['offset'] + $task['limit'];
+        // 同步数量
+        $task['sync_total'] = $task['sync_total'] + count($userList['user_list']);
+      }
+      // 更新任务总数
+      if( $userList['total'] ) {
+          // 更新任务总数
+          $task['total']                  = $userList['total'];
+          // 偏移量大于总数,更新任务状态
+          if( $task['offset']             >= $userList['total'] ) {
+              // 状态结束
+              $task['status']             = 1;
+              // 最后的修改时间
+              $task['last_time']          = $lastTime - 1;
+          }
+      }
+      // 修改任务情况
+      $Model->edit($task['id'],$task);
+    }
+
+}

+ 108 - 0
app/Console/Commands/TagRelation.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Facades\Servers\WeiBan\OpenApi;
+use App\Models\WeiBan\Sync as Model;
+use App\Jobs\WeiBanSync as WeiBanSyncJobs;
+use App\Facades\Servers\Logs\Log;
+
+class TagRelation extends Command
+{
+    /**
+     * 任务名称
+     *
+     * @var string
+     */
+    protected $signature = 'tag_relation';
+
+    /**
+     * 任务描述
+     *
+     * @var string
+     */
+    protected $description = '微伴标签数据同步任务';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+      try {
+        // 数据结果
+        $this->sync_user(new Model());
+        // 返回结果
+        return 0;
+      } catch (\Throwable $th) {
+        // 记录错误信息
+        Log::error('tag_relation',$th->getMessage());
+        // 返回结果
+        return 0;
+      }
+    }
+
+	
+    /**
+     * 客户关系同步
+     * 
+     * */
+    public function sync_user(Model $Model)
+    {
+      // 更新维度
+      $source             = 'tag_relation';
+      // 同步关系的任务
+      $task				        = $Model->getOneBySource($source);
+      // 返回结果
+      if( !$task['id'] )	return ['error'=>'无执行任务'];
+      // 获取列表
+      $userList           = OpenApi::getUserList($task['limit'],$task['offset'],$task['last_time']);
+      // 最后的更新时间
+      $lastTime           = 0;
+      // 放到队列执行
+      foreach ($userList['user_list'] as $key=>$value) {
+          // 获取最后更新时间
+          $lastTime       = $value['updated_at'];
+          // 外部联系人
+          $value          = ['id'=>$value['id']];
+          // 发送到队列执行,上锁成功则发送到队列执行
+          if( $Model->lockSyncExtidMark($value['id']) )  WeiBanSyncJobs::dispatch($value);
+          // 重组下数据
+          $userList['user_list'][$key]  = $value;
+      }
+      // 存在用户列表的话,更新OR新增
+      if( $userList['user_list'] ) {
+        // 更新下一页偏移量
+        $task['offset']     = $task['offset'] + $task['limit'];
+        // 同步数量
+        $task['sync_total'] = $task['sync_total'] + count($userList['user_list']);
+      }
+      // 更新任务总数
+      if( $userList['total'] ) {
+          // 更新任务总数
+          $task['total']                  = $userList['total'];
+          // 偏移量大于总数,更新任务状态
+          if( $task['offset']             >= $userList['total'] ) {
+              // 状态结束
+              $task['status']             = 1;
+              // 最后的修改时间
+              $task['last_time']          = $lastTime - 1;
+          }
+      }
+      // 修改任务情况
+      $Model->edit($task['id'],$task);
+    }
+
+}

+ 204 - 0
app/Console/Commands/WorkSync.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Facades\Servers\Redis\RedisLock;
+use App\Facades\Servers\WechatWork\ExternalContact;
+use App\Models\Custom;
+use App\Models\Work\Sync as Model;
+use App\Models\Work\Tag as WorkTag;
+use App\Models\Work\User as WorkUser;
+use App\Models\Work\External as WorkExternal;
+
+class WorkSync extends Command
+{
+    /**
+     * 任务名称
+     *
+     * @var string
+     */
+    protected $signature = 'work_sync';
+
+    /**
+     * 任务描述
+     *
+     * @var string
+     */
+    protected $description = '企微客户任务同步任务';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+		// 执行任务
+        $this->run_task();
+		return 0;
+    }
+
+    /**
+	 * 执行任务
+	 * 
+	 * */
+	public function run_task(){
+		// 实例
+		$Model					= New Model();
+		// 获取数据
+		$taskList				= $Model->getList();
+		// 如果没有任务列表,结束
+		if( !$taskList )		return ['error'=>'无待执行任务'];
+		// 如果没有任务列表,结束
+		$task					= array_pop($taskList);
+		// 返回结果
+		if( !$task )			return ['error'=>'无待执行任务'];
+		// 异步锁上锁,失败结束
+		if( !RedisLock::lock('work:sync:task:id',$task['id'],'180') ) return ['error'=>'任务执行中...'];
+		// 获取接待人员
+		$userIdList				= ExternalContact::getFollowUsers();
+		// 如果没有成员ID列表,结束
+		if( !$userIdList )		{
+			// 解锁
+			RedisLock::unlock('work:sync:task:id',$task['id']);
+			// 无需同步
+			return  			['error'=>'未获取到跟进人员'];
+		}
+		// 获取游标
+		$cursor					= $task['cursor'];
+		// 批量获取客户详情
+		$extUserList			= ExternalContact::batchGetByUser($userIdList,$cursor,100);
+		// 如果没有客户列表,结束
+		if( !$extUserList )		{
+			// 解锁
+			RedisLock::unlock('work:sync:task:id',$task['id']);
+			// 结束
+			return  			['error'=>'未获取到外部联系人'];
+		}
+		// 实例其他模型
+		$CustomModel			= New Custom();
+		$WorkExternalModel		= New WorkExternal();
+		$WorkUserModel			= New WorkUser();
+		$WorkTagModel			= New WorkTag();
+		// 下一页游标
+		$task['cursor']			= $extUserList['next_cursor'];
+		// 外部联系人列表
+		$extUserList 			= $extUserList['external_contact_list'];
+		// 更新的数据
+		$extUsers				= [];
+		$followUsers			= [];
+		$followTags				= [];
+		// 时间
+		$time 					= time();
+		// 循环处理
+		foreach ( $extUserList as $key=>$value ) {
+			// 外部联系人
+			$extUser						= [];
+			$extUser['name']				= $value['external_contact']['name'];
+			$extUser['avatar']				= str_ireplace('http://','https://',$value['external_contact']['avatar']);
+			$extUser['gender']				= $value['external_contact']['gender'];
+			$extUser['work_type']			= $value['external_contact']['type'];
+			$extUser['external_userid']		= $value['external_contact']['external_userid'];
+			$extUser['insert_time']			= $time;
+			$extUser['update_time']			= $time;
+			// 处理外部联系人
+			$extUsers[] 					= $extUser;
+			// 跟进客服
+			$followUser						= [];
+			$followUser['external_userid']	= $extUser['external_userid'];
+			$followUser['work_userid']		= $value['follow_info']['userid'];
+			$followUser['remark']			= $value['follow_info']['remark'];
+			$followUser['description']		= $value['follow_info']['description'];
+			$followUser['insert_time']		= $time;
+			$followUser['update_time']		= $time;
+			$followUser['remark_mobiles']	= implode(',',$value['follow_info']['remark_mobiles']);
+			$followUser['remark_company']	= empty($value['external_contact']['corp_name'])? (empty($value['follow_info']['remark_corp_name']) ? '' : $value['follow_info']['remark_corp_name']) : $value['external_contact']['corp_name'];
+			$followUsers[]					= $followUser;
+			// 跟进人员标签组合
+			foreach ( $value['follow_info']['tag_id'] as $tagId ) {
+				// 重组
+				$followTags[]				= ['tag_id'=>$tagId,'external_userid'=>$followUser['external_userid'],'work_userid'=>$followUser['work_userid'],'update_time'=>$time];
+			}
+			// 跟进人员是否备注手机号
+			$extUser['phone']				= $value['follow_info']['remark_mobiles'] ? $value['follow_info']['remark_mobiles'][0] : '';
+			// 重组数据
+			$extUserList[$key] 				= $extUser;
+		}
+		// 标签写入
+		if( $followTags )					$WorkTagModel->query()->insert($followTags);
+		// 需要更新的数据
+		$WorkExternalModel->query()->upsert($extUsers,'external_userid',['name','avatar','gender','work_type','update_time']);
+		// 需要更新的数据
+		$WorkUserModel->query()->upsert($followUsers,['external_userid','work_userid'],['remark','description','remark_mobiles','remark_company','update_time']);
+		// 获取外部联系人ID,并去重
+		$customIds							= array_values(array_unique(array_filter(array_column($extUserList,'external_userid'))));
+		// 获取外部联系人ID,并去重
+		$customPhones						= array_values(array_unique(array_filter(array_column($extUserList,'phone'))));
+		// 查询客户表中是否存在该客户
+		$customIds							= $customIds ? $WorkExternalModel->getPluckInFiled('external_userid',$customIds,'custom_uid','external_userid') : [];
+		// 获取
+		$customPhones						= $customPhones ? $CustomModel->getPluckInFiled('phone',$customPhones,'external_userid','phone') : [];
+		// 循环处理
+		foreach ( $extUserList as $value ) {
+			// 不存在外部联系人账号的跳过
+			if( !isset($customIds[$value['external_userid']]) )  continue;
+			// 存在在外部联系人账号但是绑定了账号的跳过
+			if( $customIds[$value['external_userid']] )  		 continue;
+			// 不存在手机号,跳过
+			if( !$value['phone'] )  		 					 continue;
+			// 如果绑定了其他外部联系人
+			if( !empty($customPhones[$value['phone']])  )		 continue;
+			// 账号UID默认
+			$uid												= 0;
+			// 账号未注册
+			if( !isset($customPhones[$value['phone']]) )		{
+				// 注册账号
+				$uid 											= $CustomModel->add(['phone'=>$value['phone'],'username'=>$value['name'],'userpic'=>$value['avatar'],'sex'=>$value['gender'],'external_userid'=>$value['external_userid']]);
+				// 注册失败,
+				if( !$uid )										continue;
+			}else{
+				// 已经注册的,未绑定外部联系人
+				if( !$customPhones[$value['phone']] )			{
+					// 查询号码
+					$custom										= $CustomModel->getOneByPhone($value['phone']);
+					// 没有账号,跳过
+					if( !$custom )								continue;
+					// 账号存在跳过
+					if( $custom['external_userid'] )			{
+						// 避免重复注册
+						$customPhones[$value['phone']]			= $custom['external_userid'];
+						continue;
+					}
+					// 账号UID
+					$uid										= $custom['uid'];
+				}
+			}
+			// 避免重复注册
+			$customPhones[$value['phone']]						= $value['external_userid'];
+			// 修改
+			$result												= $uid ? $WorkExternalModel->query()->where([['external_userid','=',$value['external_userid']]])->update(['custom_uid'=>$uid,'update_time'=>$time]) : true;
+			// 如果修改失败
+			if( !$result )										continue;
+			// 同步数量 +1
+			$task['sync_total'] += 1;
+		}
+		// 如果没有下一页游标,标记任务完成
+		if( !$task['cursor'] )	$task['status'] = 1;
+		// 修改任务情况
+		$Model->edit($task['id'],$task);
+		// 解锁
+		RedisLock::unlock('work:sync:task:id',$task['id']);
+	}
+
+}

+ 47 - 0
app/Console/Kernel.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Console;
+
+use Illuminate\Console\Scheduling\Schedule;
+use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
+
+class Kernel extends ConsoleKernel
+{
+    /**
+     * The Artisan commands provided by your application.
+     *
+     * @var array
+     */
+    protected $commands = [
+        //
+    ];
+
+    /**
+     * Define the application's command schedule.
+     *
+     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
+     * @return void
+     */
+    protected function schedule(Schedule $schedule)
+    {
+        // 后台任务
+        $schedule->command('staff_relation')->runInBackground();
+        // 后台任务
+        $schedule->command('staff_remark')->runInBackground();
+        // 后台任务
+        $schedule->command('tag_relation')->runInBackground();
+    }
+
+    /**
+     * Register the commands for the application.
+     *
+     * @return void
+     */
+    protected function commands()
+    {
+        // 自动引入任务命令
+        $this->load(__DIR__.'/Commands');
+        // 引入任务路由
+        require base_path('routes/console.php');
+    }
+}

+ 48 - 0
app/Exceptions/Admin/AuthException.php

@@ -0,0 +1,48 @@
+<?php namespace App\Exceptions\Admin;
+
+use Exception;
+use Throwable;
+/**
+ * 接口异常
+ */
+class AuthException extends Exception
+{
+
+    public $msg  = '';
+    public $url  = '';
+    public $wait = 3;
+
+    /**
+     * 抛出错误信息
+     * 
+     * @param   String          $msg    错误提示
+     * @param   Mixed           $url    跳转地址
+     * @param   Array           $wait   等待时间
+     * 
+     */
+    public function __construct($msg='',$url='',$wait=3)
+    {
+        $this->msg  = $msg;
+        $this->url  = $url;
+        $this->wait = $wait;
+    }
+
+    /**
+     * 错误提示
+     * 
+     */
+    public function jumpPage(){
+        $url = $this->url;
+        $msg = $this->msg;
+        $wait = $this->wait;
+        // 处理路径
+        if ( is_null($url) ) {
+            $url = request()->ajax() ? '' : 'javascript:history.back(-1);';
+        } elseif ('' !== $url) {
+            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : url($url);
+        }
+		// 返回结果
+		return		$wait ? response(view('error',['msg'=>$msg,'url'=>$url,'wait'=>$wait])) : redirect($url,302);
+    }
+
+}

+ 64 - 0
app/Exceptions/Api/ApiException.php

@@ -0,0 +1,64 @@
+<?php namespace App\Exceptions\Api;
+
+use Exception;
+use Throwable;
+/**
+ * 接口异常
+ */
+class ApiException extends Exception
+{
+
+    // 错误返回码
+    protected $errCode   = 'error';
+    // 错误返回数据
+    protected $errData   = '';
+    // 本地化前缀
+    protected $langkey   = 'message';
+    
+    /**
+     * 抛出错误信息
+     * 
+     * @param   String          $message    — [optional] The Exception message to throw.
+     * @param   Mixed           $errData    — 错误返回数据
+     * @param   Int             $code       — [optional] The Exception code.
+     * @param   Throwable       $previous   — [optional] The previous throwable used for the exception chaining.
+     * @return  Mixed
+     * 
+     */
+    public function __construct( $message="",$errData='',$code=0,?Throwable $previous=null )
+    {
+        // 如果本地化前缀存在则本地化处理
+        if( $this->langkey ) {
+            // 消息key
+            $msgKey             = $this->langkey.'.'.$message;
+            // 提示信息本地化
+            $trans              = trans($msgKey);
+            // 如果没有找到对应的提示,使用原提示信息
+            $message            = ($trans == $msgKey) ? $message : $trans;
+        }
+        // 传递数据到父级
+        parent::__construct($message, $code, $previous);
+        // 错误信息说
+        if( $errData )          $this->errData = $errData;
+    }
+
+    /**
+     * 获取错误返回码
+     * 
+     */
+    public function getErrCode()
+    {
+        return $this->errCode;
+    }
+
+    /**
+     * 获取返回数据
+     * 
+     */
+    public function getErrData()
+    {
+        return $this->errData;
+    }
+
+
+}

+ 11 - 0
app/Exceptions/Api/LoginException.php

@@ -0,0 +1,11 @@
+<?php namespace App\Exceptions\Api;
+
+
+class LoginException extends ApiException
+{
+
+    // 错误返回码
+    protected $errCode   = 'no_login';
+    // 本地化前缀
+    protected $langkey   = 'api_login';
+}

+ 15 - 0
app/Exceptions/Api/ValidException.php

@@ -0,0 +1,15 @@
+<?php namespace App\Exceptions\Api;
+
+
+/**
+ * 接口验证签名错误抛出
+ * 
+ */
+class ValidException extends ApiException
+{
+
+    // 错误返回码
+    protected $errCode   = 'error';
+    // 本地化前缀
+    protected $langkey   = '';
+}

+ 15 - 0
app/Exceptions/Api/VerifySignException.php

@@ -0,0 +1,15 @@
+<?php namespace App\Exceptions\Api;
+
+
+/**
+ * 接口验证签名错误抛出
+ * 
+ */
+class VerifySignException extends ApiException
+{
+
+    // 错误返回码
+    protected $errCode   = 'no_access';
+    // 本地化前缀
+    protected $langkey   = 'api_access';
+}

+ 90 - 0
app/Exceptions/Handler.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace App\Exceptions;
+
+use App\Exceptions\Admin\AuthException;
+use App\Exceptions\Api\ApiException;
+use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use App\Facades\Servers\Logs\Log;
+use Throwable;
+
+class Handler extends ExceptionHandler
+{
+    /**
+     * 不报告的异常类型的列表
+     *
+     * @var array
+     */
+    protected $dontReport = [
+        //
+    ];
+
+    /**
+     * A list of the inputs that are never flashed for validation exceptions.
+     *
+     * @var array
+     */
+    protected $dontFlash = [
+        'current_password',
+        'password',
+        'password_confirmation',
+    ];
+
+    /**
+     * Register the exception handling callbacks for the application.
+     *
+     * @return void
+     */
+    public function register()
+    {
+        $this->reportable(function (Throwable $e) {
+
+        })->stop();
+    }
+
+
+    /**
+     * 将异常呈现到HTTP响应中
+     * 
+     * 
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function render($request, Throwable $e){
+        // 如果不是接口,
+        if( !$request->is('api/*') )   {
+            // 如果是后端验证类
+            if( $e instanceof AuthException )  return $e->jumpPage();
+            // 如果不是验证返回,调用父级异常呈现
+            if( !($e instanceof ApiException) ) return parent::render($request, $e);
+        }
+        // 如果是异常类型,获取异常的消息
+        $msg            = $e->getMessage();
+        // 错误信息
+        $msg            = $msg ? $msg : '404';
+        // 错误数据
+        $data           = '';
+        // 错误码
+        $code           = 'sys_error';
+        // http状态码
+        $status         = 200;
+        // 日志信息
+        $message         = request()->ip().' ' .request()->method().' '. request()->getPathInfo().' '.$msg;
+        // 如果是接口异常
+        if( $e instanceof ApiException ){
+            // 错误码
+            $code       = $e->getErrCode();
+            // 错误数据
+            $data       = $e->getErrData();
+        }else{
+            // 拼接报错文件位置
+            $message    .= ' of file '.$e->getFile().' on line '.$e->getLine();
+        }
+        // 要返回的数据
+        $data           = ['code'=>($code == 'sys_error' ? 'error' : $code),'msg'=>$msg,'data'=>$data];
+        // 记录日志
+        Log::info($code,$message,['param'=>request()->all(),'return'=>$data,'user_agent'=>request()->header('user-agent')],['filename'=>str_ireplace('/','_',trim(request()->getPathInfo(),'/'))]);
+        // 返回结果
+        return          response()->json($data,$status,[],JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
+    }
+
+}

+ 24 - 0
app/Facades/Servers/Encrypts/AccessToken.php

@@ -0,0 +1,24 @@
+<?php namespace App\Facades\Servers\Encrypts;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 自定义简单对称加密
+ * 
+ * @see \App\Servers\Encrypts\AccessToken
+ * 
+ */
+class AccessToken extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Encrypts\AccessToken';
+    }
+}
+
+?>

+ 26 - 0
app/Facades/Servers/Encrypts/ApiSign.php

@@ -0,0 +1,26 @@
+<?php namespace App\Facades\Servers\Encrypts;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 接口签名
+ * 
+ * @staticmethod array encode( array $contents ,string $appid, string $appkey)  加密
+ * 
+ * @see \App\Servers\Encrypts\ApiSign
+ * 
+ */
+class ApiSign extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Encrypts\ApiSign';
+    }
+}
+
+?>

+ 24 - 0
app/Facades/Servers/Encrypts/Simple.php

@@ -0,0 +1,24 @@
+<?php namespace App\Facades\Servers\Encrypts;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 自定义简单对称加密
+ * 
+ * @see \App\Servers\Encrypts\Simple
+ * 
+ */
+class Simple extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Encrypts\Simple';
+    }
+}
+
+?>

+ 29 - 0
app/Facades/Servers/Logs/Log.php

@@ -0,0 +1,29 @@
+<?php namespace App\Facades\Servers\Logs;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * @method static mixed log(string $name,string $message,array $content=[],int $level=Logger::INFO,array $options=[])
+ * @method static mixed  debug(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  info(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  notice(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  warning(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  error(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  critical(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  alert(string $name,string $message,array $content=[],array $options=[])
+ * @method static mixed  emergency(string $name,string $message,array $content=[],array $options=[])
+ * 
+ * @see \App\Servers\Logs\Log
+ */
+class Log extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return 'App\Servers\Logs\Log';
+    }
+}

+ 33 - 0
app/Facades/Servers/Redis/Redis.php

@@ -0,0 +1,33 @@
+<?php namespace App\Facades\Servers\Redis;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * @method static  \Illuminate\Redis\Connections\Connection connection(string $name = null)
+ * @method static  \Illuminate\Redis\Limiters\ConcurrencyLimiterBuilder funnel(string $name)
+ * @method static  \Illuminate\Redis\Limiters\DurationLimiterBuilder throttle(string $name)
+ * @method static bool     set(string $key,string $value,['EX'|'PX'],[$expire],['NX'|'XX'])   设置指定key的值 
+ * @method static mixed    get(string $key)      获取指定key的值 
+ * @method static bool setex(string $key,int $seconds,string $value) 将值value关联到key,并将key的过期时间设为seconds(以秒为单位)。
+ * @method static bool pErsist(string $key)     移除给定key的过期时间,使得key永不过期
+ * @method static bool expire(string $key,int $expire)     为给定key设置生存时间
+ * @method static bool del(mixed $key,...$otherkey)   删除已存在的键。不存在的 key 会被忽略
+ * @method static int setBit(string $key,int $offset, int$value)   设置或清除指定偏移量上的位(bit)。返回值是:指定偏移量原来储存的位$value
+ * @method static int getBit(string $key,int $offset)          获取指定偏移量上的位(bit)。返回值是:字符串值指定偏移量上的位(bit)。当偏移量 OFFSET 比字符串值的长度大,或者 key 不存在时,返回 0 。
+ * @method static int exists(string $key)         检查给定 key 是否存在,若 key 存在返回 1 ,否则返回 0 。
+ * 
+ * @see \Illuminate\Redis\RedisManager
+ * @see \Illuminate\Contracts\Redis\Factory
+ */
+class Redis extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return 'redis';
+    }
+}

+ 23 - 0
app/Facades/Servers/Redis/RedisLock.php

@@ -0,0 +1,23 @@
+<?php namespace App\Facades\Servers\Redis;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * @method static miexd lock(string $key,string $value, int $ex=20)     上异步锁
+ * @method static miexd unlock($key,$value)          释放锁
+ * 
+ * @see \App\Servers\Redis\RedisLock
+ * 
+ */
+class RedisLock extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return 'App\Servers\Redis\RedisLock';
+    }
+}

+ 28 - 0
app/Facades/Servers/Tencent/Cos.php

@@ -0,0 +1,28 @@
+<?php namespace App\Facades\Servers\Tencent;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 对象存储
+ * 
+ * @method  array listObjectsAll($prefix='',$filter_name='',$marker='',$maxkeys=16,$delimiter='/',$result=[])   获取指定目录下的所有对象
+ * @method  array|string upload($key,$body,$headers=[])     上传对象
+ * @method  array|bool deleteObject($key,$versionId=null)   删除单个对象
+ * 
+ * @see \App\Servers\Tencent\Cos
+ * 
+ */
+class Cos extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Tencent\Cos';
+    }
+}
+
+?>

+ 24 - 0
app/Facades/Servers/Tencent/Sms.php

@@ -0,0 +1,24 @@
+<?php namespace App\Facades\Servers\Tencent;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 短信发送
+ * 
+ * @see \App\Servers\Tencent\Sms
+ * 
+ */
+class Sms extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\Tencent\Sms';
+    }
+}
+
+?>

+ 30 - 0
app/Facades/Servers/WechatMini/Mini.php

@@ -0,0 +1,30 @@
+<?php namespace App\Facades\Servers\WechatMini;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 对象存储
+ * 
+ * @method static string getUrlLink($path,$query='')     获取UrlLink
+ * @method static array  getUserPhone($code)        手机号授权
+ * @method static string  getAccessToken()          获取AccessToken
+ * @method static mixed  queryUrlLink($urlLink)     查询加密UrlLink
+ * 
+ * 
+ * @see \App\Servers\WechatMini\Mini
+ * 
+ */
+class Mini extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatMini\Mini';
+    }
+}
+
+?>

+ 30 - 0
app/Facades/Servers/WechatWork/ContactWay.php

@@ -0,0 +1,30 @@
+<?php namespace App\Facades\Servers\WechatWork;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 联系我
+ * 
+ * @method static array getList(string $cursor,int $limit=10)            获取列表
+ * @method static array getOne(string $configId)                         获取详情
+ * @method static array add(string $config,int $type=2,int $scene=2)     添加
+ * @method static string edit(string $configId,array $config)            编辑
+ * @method static string del(string $configId)                           删除
+ * 
+ * @see \App\Servers\WechatWork\ContactWay
+ * 
+ */
+class ContactWay extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatWork\ContactWay';
+    }
+}
+
+?>

+ 34 - 0
app/Facades/Servers/WechatWork/CorpTag.php

@@ -0,0 +1,34 @@
+<?php namespace App\Facades\Servers\WechatWork;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 标签管理
+ * 
+ * @method static array getList(array $tagIds=[],array $groupIds=[])           获取列表
+ * @method static array getOne(string $configId)                               获取详情
+ * @method static array upsertTag($groupName,$tag)                             不存在则更新标签
+ * @method static array add(array $params)                                     添加
+ * @method static bool  edit(string $id,string $name,int $order)               编辑
+ * @method static bool  del(array $tagIds,array $groupIds)                     删除
+ * @method static bool  markTags(string $userId,string $extUserid,array $addTag=[],array $removeTag=[])  给客户打标签
+ * @method static bool  markCityTag($workUserId,$extuserId,$province,$city)    给客户打上省份城市标签
+ * @method static array upsertTag($groupName,$tag)                             不存在则更新标签
+ * 
+ * @see \App\Servers\WechatWork\CorpTag
+ * 
+ */
+class CorpTag extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatWork\CorpTag';
+    }
+}
+
+?>

+ 30 - 0
app/Facades/Servers/WechatWork/Department.php

@@ -0,0 +1,30 @@
+<?php namespace App\Facades\Servers\WechatWork;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 部门管理
+ * 
+ * @method static array getList($id=null)             获取列表
+ * @method static array getOne(int $id)               获取详情
+ * @method static int   add(array $data)              添加
+ * @method static int   edit(int $id,array $data)     编辑
+ * @method static int   del($id)                      删除
+ * 
+ * @see \App\Servers\WechatWork\Department
+ * 
+ */
+class Department extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatWork\Department';
+    }
+}
+
+?>

+ 30 - 0
app/Facades/Servers/WechatWork/ExternalContact.php

@@ -0,0 +1,30 @@
+<?php namespace App\Facades\Servers\WechatWork;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 客户管理
+ * 
+ * @method static array  getFollowUsers()                                               获取配置了客户联系功能的成员列表
+ * @method static array  batchGetByUser(array $userIdList,string $cursor,int $limit=100) 批量获取客户详情
+ * @method static array  getOne(string $extUserid)                                      获取客户详情
+ * @method static bool   sendWelcome(string $welcomeCode, array $msg)                   发送欢迎语
+ * @method static bool   remark($extUserid, $userid,$data=[])                           修改客户备注
+ * 
+ * @see \App\Servers\WechatWork\ExternalContact
+ * 
+ */
+class ExternalContact extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatWork\ExternalContact';
+    }
+}
+
+?>

+ 28 - 0
app/Facades/Servers/WechatWork/User.php

@@ -0,0 +1,28 @@
+<?php namespace App\Facades\Servers\WechatWork;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 对象存储
+ * 
+ * @method static array getList(string $departId,bool $fetchChild=false)   获取某个部门成员列表
+ * @method static array getListDepart()                                    获取所有部门的成员
+ * @method static array|string getOne(string $userid)                      获取成员详情
+ * 
+ * @see \App\Servers\WechatWork\User
+ * 
+ */
+class User extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WechatWork\User';
+    }
+}
+
+?>

+ 29 - 0
app/Facades/Servers/WeiBan/OpenApi.php

@@ -0,0 +1,29 @@
+<?php namespace App\Facades\Servers\WeiBan;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 对象存储
+ * 
+ * @method static string getAccessToken()                                                                   获取凭证
+ * @method static array  getUserList(int $limit,int $offset,int $startTime=0,string $source='remark')       获取用户列表
+ * @method static array  getUserDetail(string $id)                                                          获取用户详情
+ * 
+ * 
+ * @see \App\Servers\WeiBan\OpenApi
+ * 
+ */
+class OpenApi extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return '\App\Servers\WeiBan\OpenApi';
+    }
+}
+
+?>

+ 370 - 0
app/Helpers/functions.php

@@ -0,0 +1,370 @@
+<?php
+
+use App\Facades\Servers\Logs\Log;
+use Illuminate\Support\Facades\DB;
+use Intervention\Image\Facades\Image;
+/**
+ * 响应请求
+ * @param	Mixed		$data	数据
+ * @param	String		$code	状态码
+ * @param	Mixed		$log	是否记录日志
+ * 
+ * */
+function json_send($data,$code=200){
+    // 日志名称
+    $name                   = empty($data['code']) ? 'unknown' : $data['code'];
+    // 获取提示消息
+    $msg                    = empty($data['msg']) ? '' : $data['msg'];
+    // 如果提示数据不是成功或者是local
+    if( $name != 'success' || config('app.env') == 'local' ) {
+        // 消息key
+        $msgKey             = 'message.'.$msg;
+        // 提示信息本地化
+        $trans              = trans($msgKey);
+        // 如果没有找到对应的提示,使用原提示信息
+        $data['msg']        = ( $trans == $msgKey ) ? $msg : $trans;
+        // 消息
+        $msg                = request()->ip().' ' .request()->method().' '. request()->getPathInfo().' '.$msg;
+        // 记录内容
+        $content            = ['param'=>request()->all(),'return'=>$data,'user_agent'=>request()->header('user-agent')];
+        // 记录日志
+        Log::info($name,$msg,$content,['filename'=>str_ireplace('/','_',trim(request()->getPathInfo(),'/'))]);
+    }
+    // 默认返回数据
+    $data['data']           = isset($data['data']) ? $data['data'] : '';
+	// 返回数据
+	return			        response()->json($data,$code,[],JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
+}
+
+/**
+ * 雪花算法生成分布式ID
+ * 
+ * @param	Int		    $dataCenterId   数据中心ID 0-31
+ * @param	Int		    $machineId     任务进程ID 0-31
+ * 
+ * @return	String		分布式ID
+ * */
+function make_snow_flake($dataCenterID=0,$machineId=0){
+    // 获取redis配置
+    $redis              = config('database.redis.default');
+    // 主机地址
+    $config['host']     = empty($redis['host'])  ? '127.0.0.1' : $redis['host'];
+    // 端口
+    $config['port']     = empty($redis['port'])  ? 6379 : $redis['port'];
+    // 密码
+    if( !empty($redis['password']) )  $config['auth']       = $redis['password'];
+    // 数据库
+    if( !empty($redis['database']) )  $config['dbIndex']    = $redis['database'];
+    // 实例化
+    $IdWorker           = \wantp\Snowflake\IdWorker::getIns($dataCenterID,$machineId);
+    // 生成
+    return              $IdWorker->setRedisCountServer($config)->id();
+}
+
+
+/**
+ * 终端设备系统
+ * 
+ * @param	String		$agent 		HTTP_USER_AGENT数据
+ * 
+ * */
+function get_agent_system($agent=''){
+    //HTTP_USER_AGENT数据
+    $agent								= $agent ? $agent : request()->header('user-agent');
+    //iOS
+    if( stripos($agent, 'iphone') || stripos($agent, 'ipad') ) return 'iOS';
+    //iOS
+    if( stripos($agent, 'macintosh') )	return 'MacOS';
+    //安卓
+    if( stripos($agent, 'android') ) 	return 'Android';
+    //安卓
+    if( stripos($agent, 'okhttp') ) 	return 'Android';
+    //Windows
+    if( stripos($agent, 'win') ) 		return 'Windows';
+    //Linux
+    if( stripos($agent, 'linux') )		return 'Linux';
+    //Unix
+    if( stripos($agent, 'unix') )		return 'Unix';
+    //Other
+    return 'Other';
+}
+
+/**
+ * 路径兼容输出
+ * 
+ * @param	String	    $url	文件路径
+ * @param	Int|NUll	$width  新图片宽度
+ * @param	Int|NUll	$height 新图片高度(如果没有填写高度,把高度等比例缩小)
+ * @param	String		$type 	文件类型
+ * 
+ * @author	刘相欣
+ * */
+function path_compat( $url,$witdh=null,$higth=null,$type='') {
+    // 没有路径的统一返回原数据
+    if( !$url )             return $type ? $url : request()->root().'/'.ltrim(resize($url,$witdh,$higth),'/');
+    // 如果是带有http的路径,直接返回
+    if( stripos('$'.$url, 'http') ) {
+        // 腾讯云链
+        if( stripos( $url, 'myqcloud.com') ){
+            // 开启全球域名全球加速时, 替换COS全球加速域名
+            if( config('open_accelerate','') )  $url = str_ireplace('.cos.'.config('tencent.cos.region','').'.myqcloud.com','.cos.accelerate.myqcloud.com',$url);
+            // 如果需要开启CDN,局部开启,全局开启
+            if( request()->is('api/*') && (request('open_cdn',0) || config('open_cdn',0) ) && config('open_cdn_domain','') ){
+                // 先把https 换成 http
+                $url = str_ireplace('https','http',$url);
+                // 替换域名
+                $url = str_ireplace(config('tencent.cos.bucket','').'-'.config('tencent.cos.app_id','').'.cos.'.config('tencent.cos.region','').'.myqcloud.com',config('open_cdn_domain',''),$url);
+            }
+        }
+        // 获取扩展信息
+        $type		        = strtolower(pathinfo($url, PATHINFO_EXTENSION));
+        // 如果信息不存在
+        if( !$type )        return $url;
+        // 不是图片直接返回路径
+        if( !in_array($type,['jpg','png','jpeg','gif','bmp']) ) return $url;
+        // 需要后缀的OSS参数
+        $param		        = '';
+        // 阿里云的OSS
+        if( stripos( $url, 'aliyuncs.com') ){
+            // 判断图片的宽高进行缩放处理
+            if( $witdh && $higth ){
+                // 宽高都存在时,固定宽高,将延伸出指定w与h的矩形框外的最小图片进行居中裁剪
+                $param      = '?x-oss-process=image/resize,m_fill,limit_0,w_'.$witdh.',h_'.$higth;
+            }else if($witdh){
+                $param      = '?x-oss-process=image/resize,w_'.$witdh;
+            }else if($higth){
+                $param      = '?x-oss-process=image/resize,h_'.$higth;
+            }
+        }
+        // 腾讯云的COS
+        if( stripos( $url, 'myqcloud.com') ){
+            if( $witdh && $higth ){
+                // 宽高都存在时,固定宽高,将延伸出指定w与h的矩形框外的最小图片进行居中裁剪
+                $param	= '?imageView2/2/w/'.$witdh.'/h/'.$higth;
+            }else if($witdh){
+                $param	= '?imageView2/2/w/'.$witdh;
+            }else if($higth){
+                $param	= '?imageView2/2/h/'.$higth;
+            }
+        }
+        // 路径
+        return $param ? $url.$param : $url;
+    }
+    // 类型
+    $type		        = strtolower(pathinfo($url, PATHINFO_EXTENSION));
+    // 是图片则返回缩略图
+    if( in_array($type,['jpg','png','jpeg','gif','bmp']) )  return rtrim((config('img_cdn_domain')?config('img_cdn_domain'):request()->root()),'/').'/'.ltrim(resize($url,$witdh,$higth),'/');
+    // 判断是否存在文件
+    if( file_exists('uploads/'.$url) )                      return request()->root().'/uploads/'.ltrim($url,'/');
+    // 其他类型文件,统一返回
+    return              request()->root().'/'.ltrim($url,'/');
+}
+
+/**
+ * 自动生成新尺寸 的图片
+ * @param string $filename 文件名
+ * @param int $width 新图片宽度
+ * @param int $height 新图片高度(如果没有填写高度,把高度等比例缩小)
+ */
+function resize( $filename, $width=null, $height=null) {
+    // 如果不存在图片路径
+    if( !is_file(DIR_IMAGE.$filename)||empty($filename) )  $filename = config('app.no_pic');
+    // 如果没有宽高,给原图
+    if( !$width && !$height ) return 'uploads/'.$filename;
+    // 调整当前图像的边界到给定的宽和高
+    $img        = Image::make(DIR_IMAGE.$filename)->resizeCanvas($width, $height);
+    // 获取文件名称
+    $name       = pathinfo($filename,PATHINFO_FILENAME);
+    // 缓存名
+    $cacheName  = $width ? $name.'_w' .$width : $name;
+    $cacheName  = $height ? $cacheName.'_h' .$height : $cacheName;
+    // 名称拼接宽高
+    $filename   = str_replace($name,$cacheName,$filename);
+    // 缓存文件路径
+    $newFile    = 'cache/'.$filename;
+    // 如果目录不存在,创建目录
+    if( !is_dir(dirname(DIR_IMAGE.$newFile)) ) mkdir(dirname(DIR_IMAGE.$newFile),0755,true);
+    // 保存新图
+    $img->save(DIR_IMAGE.$newFile);
+    // 返回结果
+    return      'uploads/'.$newFile;
+}
+
+/**
+ * 获取网站后台管理员信息
+ * @param	[String]		$key	字段键名
+ * 
+ * @return	[String]
+ */
+function admin($key){
+	// 从会话中读取
+	$admin                      = session('userAuth');
+	// 返回数据
+	if( empty($admin) )         return null;
+	// 存在字段数据,并且存在用户ID
+	if( isset($admin[$key]) )   return $admin[$key];
+	// 没有用户ID
+	if( empty($admin['uid']) )  return null;
+	// 查询用户数据	
+	$user                       = DB::table('admin')->where(['uid'=>$admin['uid']])->first();	
+	// 如果字段存在
+	if( isset($user[$key]) )    return $user[$key];
+	// 返回错误字段
+	return                      null;
+}
+
+
+/**
+ * 检查用户操作权限
+ * @param String $route  路径
+ */
+function check_auth($route){
+    // 超管不限制
+    if(in_array(admin('uid'), explode(',', config('administrator'))) ) return true;
+    // 验证结果
+    if(in_array($route,request()->authRules)) return true;
+    // 默认无权限
+    return                      false;
+}
+
+
+/**
+ * 把返回的数据集转换成Tree
+ * @param	[Array]		$list	要转换的数据集
+ * @param	[String]	$pid	parent标记字段
+ * @param	[String]	$level	level标记字段
+ * @return	[Array]
+ * 
+ * @author	麦当苗儿 <zuojiazi@vip.qq.com>
+ * 
+ */
+function list_to_tree($list, $pk='id', $pid = 'pid', $child = 'children', $root = 0) {
+    // 创建Tree
+    $tree = array();
+    if(is_array($list)) {
+        // 创建基于主键的数组引用
+        $refer = array();
+        foreach ($list as $key => $data) {
+            $refer[$data[$pk]] =& $list[$key];
+        }
+        foreach ($list as $key => $data) {
+            // 判断是否存在parent
+            $parentId =  $data[$pid];
+            if ($root == $parentId) {
+                $tree[] =& $list[$key];
+            }else{
+                if (isset($refer[$parentId])) {
+                    $parent =& $refer[$parentId];
+                    $parent[$child][] =& $list[$key];
+                }
+            }
+        }
+    }
+    return $tree;
+}
+
+/**
+ * 格式化字节
+ * @param	Int $byte 		字节数值
+ * 
+ * */
+function byte_format($byte){
+    // 如果是GB
+    if( $byte >= (1024 * 1024 * 1024) )		return round( $byte / (1024 * 1024 * 1024),2 ).' GB';
+    // 如果是MB
+    if( $byte >= (1024 * 1024) )			return round( $byte / (1024 * 1024),2 ).' MB';
+    // 如果是KB
+    if( $byte >= (1024) )					return round( $byte / (1024),2 ).' KB';
+    // 如果是字节
+    return $byte.' B';
+}
+
+/**
+ * 二维数组排序,根据某个字段
+ * @param   Array       $array      要排序的数组
+ * @param   String      $key        要排序的键字段
+ * @param   String      $sort       排序类型 SORT_ASC SORT_DESC 
+ * @return  Array       排序后的数组
+ */
+function array_sort($array, $key, $sort = SORT_DESC) {
+    // 获取字段数据
+    $keys       = array_column($array,$key);
+    // 进行排序
+    array_multisort($keys, $sort, $array);
+    // 返回结果
+    return      $array;
+}
+
+/**
+ * 二维数组排序,根据某个字段
+ * @param   string      $phoneNumber        手机号
+ */
+function hide_phone($phoneNumber) {
+    return substr_replace($phoneNumber, '****', 3, 4);
+}
+
+
+/**
+ * 省份去除自治区等后缀
+ * 
+ * @param   string      $province       省份
+ * 
+ */
+function province_rtrim($province) {
+    // 长度2个字的不处理
+    if( mb_strlen($province) <= 2 ) return $province;
+    // 省份信息
+    $province   = str_ireplace(['省','回族','维吾尔','壮族','自治区','特别行政区'],'',$province);
+    // 返回结果
+    return      $province;
+}
+
+/**
+ * 城市去除自治州等后缀
+ * 
+ * 
+ * @param   string      $city       地级市单位
+ * 
+ */
+function city_rtrim($city) {
+    // 长度2个字的不处理
+    if( mb_strlen($city) <= 2 ) return $city;
+    // 名称
+    $result             = mb_strrchr($city,'市',true);
+    // 返回结果
+    if( $result )       return $result;
+    // 名称
+    $result             = mb_strrchr($city,'自治州',true);
+    // 返回结果
+    if( $result )       return $result;
+    // 名称
+    $result             = mb_strrchr($city,'盟',true);
+    // 返回结果
+    if( $result )       return $result;
+    // 名称
+    $result             = mb_strrchr($city,'地区‌',true);
+    // 返回结果
+    if( $result )       return $result;
+    // 返回结果
+    return              $city;
+}
+
+/**
+ * 将字符串追加到某个需要切割成数组的字符串数组
+ * 
+ * 
+ * @param   string      $dest    目标字符串
+ * @param   string      $source  需要追加的字符串
+ * @param   string      $sep     目标字符串切割方式
+ * 
+ */
+function push_str_arr($dest,$source,$sep=',') {
+    // 转数组
+    $result			= $dest ? explode($sep,$dest) : [];
+    $result[]		= $source;
+    $result			= array_values(array_unique($result));
+    // 返回结果
+    return          $result;
+}
+
+?>

+ 40 - 0
app/Http/Controllers/Admin/Admin.php

@@ -0,0 +1,40 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Controllers\Controller;
+use App\Models\AdminHistory;
+
+/**
+ * 后台控制器
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Admin extends Controller{
+	
+	/**
+	 * 构造方法,初始化
+	 * 
+	 * */
+	public function __construct(){
+		// 执行父级的先
+		parent::__construct();
+	}
+
+	/**
+	 * 保存用户操作历史
+	 * 
+	 * @param   Int         $uid        用户ID
+     * @param   String      $table      操作表
+     * @param   Int         $type       操作类型
+     * @param   Array       $oldData    旧数据
+     * @param   Array       $oldData    新数据
+	 * 
+	 */
+	protected function addAdminHistory($uid,$table,$id,$type,$oldData,$newData) {
+		//记录详细操作历史
+		$AdminHistory			= (new AdminHistory());
+		// 记录数据
+		$AdminHistory->addAll($uid,$table,$id,$type,$oldData,$newData);
+	}
+
+}

+ 63 - 0
app/Http/Controllers/Admin/AdminHistory.php

@@ -0,0 +1,63 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\AdminUser;
+use App\Models\AdminHistory as Model;
+
+/**
+ * 操作记录
+ *
+ * @author    刘相欣
+ *
+ */
+class AdminHistory extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','操作记录');
+		$this->assign('breadcrumb2','操作列表');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser){
+		// 接收参数
+		$table				= request('table','');
+		$primaryId        	= request('primary_id',0);
+		$notesType        	= request('notes_type',0);
+		$AdminUid        	= request('admin_uid','');
+		// 查询条件
+		$map				= [];
+		// 组合条件
+		if( $table )		$map[] = ['table_name','=',$table];
+		if( $primaryId )	$map[] = ['primary_id','=',$primaryId];
+		if( $notesType )	$map[] = ['notes_type','=',$notesType];
+		if( $AdminUid )		$map[] = ['admin_uid','=',$AdminUid];
+		// 查询数据
+		$list 				= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10))->appends(request()->all());
+		// 循环处理
+		foreach ($list as $key => $value) {
+			// 获取类型
+			$value['notes_type']    = $value['notes_type'] == 1 ? '添加' : ($value['notes_type'] == 2 ? '修改' : '删除');
+			// 获取字段名称
+			$value['column_name']   = $Model->getTableColumn($value['table_name'],$value['column_name']);
+			// 获取表名称
+			$value['table_name']    = $Model->getTableName($value['table_name']);
+			// 获取操作人
+			$value['admin_name']    = $AdminUser->getOne($value['admin_uid'],'username');
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 获取结果
+		$adminUsers					= $AdminUser->getList();
+		// 分配数据
+		$this->assign('list', $list);
+		$this->assign('adminUsers', $adminUsers);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return						$this->fetch();   
+    }
+	
+
+}

+ 255 - 0
app/Http/Controllers/Admin/AdminUser.php

@@ -0,0 +1,255 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\AdminUser as Request;
+use App\Models\AdminUser as Model;
+use Illuminate\Support\Facades\DB;
+/**
+ * 系统用户
+ *
+ * @author    刘相欣
+ *
+ */
+class AdminUser extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','用户管理');
+		$this->assign('breadcrumb2','后台管理员');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model){
+ 		// 查询系统用户
+		$list					= $Model->orderByDesc('uid')->paginate(config('page_num',10));
+		// 循环处理
+		foreach ($list as $key => $value) {
+			// 获取分组名
+			$group				= DB::table('auth_group')
+									->join('auth_group_access','auth_group_access.group_id','=','auth_group.id')
+									->where([['auth_group_access.user_uid','=',$value['uid']]])
+									->pluck('auth_group.title')->toArray();
+			if (in_array($value['uid'],explode(',',config('administrator')))) $group[] = '超管';
+			// 切成字符串
+			$value['title']		= implode('、', $group);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return $this->fetch();   
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			$data['password']		= request('password','');
+			$data['password']		= md5($data['password']);
+			// 所属权限组
+			$groups					= (array) request('groups',[]);
+			// 开启事务
+			DB::beginTransaction();
+			// 写入数据表
+			$uid					= $Model->add($data);
+			// 如果操作失败
+			if( !$uid ) {
+				// 回滚事务
+    			DB::rollBack();
+				// 告知错误
+				return				json_send(['code'=>'error','msg'=>'新增失败']);
+			}
+			// 权限组
+			$access					= [];
+			// 循环数据
+			foreach ( $groups as $group_id) {
+				// 追加数据
+				$access[]			= ['group_id'=>$group_id,'user_uid'=>$uid];
+			}
+			// 写入用户权限组
+			$result					= DB::table('auth_group_access')->insert($access);
+			// 如果操作失败
+			if( !$result ) {
+				// 回滚事务
+    			DB::rollBack();
+				// 告知错误
+				return				json_send(['code'=>'error','msg'=>'权限分配失败']);
+			}
+			// 提交事务
+    		DB::commit();
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		$whereGroup = [];
+		// 如果不是超管 查询当前用户所属组
+		$administrator = explode(',', config('administrator'));
+		if(!in_array(admin('uid'),$administrator)){
+		    //用户所属组
+			$gsGroup = DB::table('auth_group_access')->where(['user_uid'=>admin('uid')])->pluck('group_id')->toArray();
+			//用户所属组 上级
+			$upGroup = DB::table('auth_group')->whereIn('id',$gsGroup)->pluck('group_pid')->toArray();
+			//用户所属组的下级
+			$groupLower = DB::table('auth_group')->whereIn('group_pid',$gsGroup)->pluck('id')->toArray();
+			//var_dump($groupLower);
+		    $whereGroup = array_merge($upGroup,$gsGroup,$groupLower);
+		}
+		// 查询用户组
+	    $query 						= DB::table('auth_group');
+	    if($whereGroup) 			$query->whereIn('id',$whereGroup);
+		$group						= $query->whereNotIn('id',explode(',',config('CUSTOM_GROUP')))->select(['id','title'])->get()->toArray();
+		// 错误告知
+		if( !$group )				$this->error('请先添加用户组');
+		// 分配数据
+		$this->assign('group',$group);
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接收参数
+		$uid						= request('uid',0);
+		// 查询用户
+		$oldData					= $Model->where(['uid'=>$uid])->first();
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			// 密码
+			$password				= request('password','');
+			// 所属权限组
+			$groups					= (array) request('groups',[]);
+			// 如果用户不存在
+			if( !$oldData )			return json_send(['code'=>'error','msg'=>'用户不存在']);
+			// 不能修改超管的账号
+			if( $oldData['username'] == config('administrator') )	return json_send(['code'=>'error','msg'=>'这是被禁止的操作']);
+			// 如果要修密码
+			if( $password ) 		$data['password'] = md5($password);
+			// 开启事务
+			DB::beginTransaction();
+			// 写入数据表
+			$result					= $Model->edit($uid,$data);
+			// 如果操作失败
+			if( !$result ) {
+				// 回滚事务
+    			DB::rollBack();
+				// 告知错误
+				return				json_send(['code'=>'error','msg'=>'新增失败']);
+			}
+			// 清空权限组
+			DB::table('auth_group_access')->where([['user_uid','=',$uid]])->delete();
+			// 权限组
+			$access					= [];
+			// 循环数据
+			foreach ( $groups as $group_id) {
+				// 追加数据
+				$access[]			= ['group_id'=>$group_id,'user_uid'=>$uid];
+			}
+			// 写入用户权限组
+			$result					= DB::table('auth_group_access')->insert($access);
+			// 如果操作失败
+			if( !$result ) {
+				// 回滚事务
+    			DB::rollBack();
+				// 告知错误
+				return				json_send(['code'=>'error','msg'=>'权限分配失败']);
+			}
+			// 提交事务
+    		DB::commit();
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		$whereGroup = [];
+		// 如果不是超管 查询当前用户所属组
+		$administrator = explode(',', config('administrator'));
+		if(!in_array(admin('uid'),$administrator)){
+		    // 用户所属组
+			$gsGroup				= DB::table('auth_group_access')->where(['user_uid'=>admin('uid')])->pluck('group_id')->toArray();
+			// 用户所属组 上级
+			$upGroup				= DB::table('auth_group')->whereIn('id',$gsGroup)->pluck('group_pid')->toArray();
+			// 用户所属组的下级
+			$groupLower				= DB::table('auth_group')->whereIn('group_pid',$gsGroup)->pluck('id')->toArray();
+			// 下属组
+		    $whereGroup				= array_merge($upGroup,$gsGroup,$groupLower);
+		}
+		// 查询用户组
+	    $query 						= DB::table('auth_group');
+		// 查询组
+	    if($whereGroup)  			$query->whereIn('id',$whereGroup);
+		// 获取
+		$group						= $query->whereNotIn('id',explode(',',config('CUSTOM_GROUP')))->select(['id','title'])->get()->toArray();
+		// 错误告知
+		if( !$group )				return $this->error('请先添加用户组');
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 查询用户的用户组
+		$oldData['group']			= DB::table('auth_group_access')->where([['user_uid','=',$uid]])->pluck('group_id')->toArray();
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('group',$group);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 操作历史
+	 * 
+	 * */
+    public function history(){
+ 		// 查询
+		$list = DB::table('user_action')->orderByDesc('ua_id')->paginate(config('page_num',10))->appends(request()->all());
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+    	$this->assign('breadcrumb2','操作记录');
+		$this->assign('list',$list);
+		// 加载模板
+		return $this->fetch();   
+    }
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$id				= request('uid',0);
+		$status			= request('status',0);
+		// 查询用户
+		$oldData		= $Model->where(['uid'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status]);		
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 73 - 0
app/Http/Controllers/Admin/Auth.php

@@ -0,0 +1,73 @@
+<?php namespace App\Http\Controllers\Admin;
+
+
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 后台控制器
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Auth extends Admin{
+	
+
+    /**
+     * 获得菜单
+     * 
+     * */
+    protected function getMenu($module = '')
+    {
+        // 获得菜单,如果不是管理员,获得需要验证的菜单
+        $adminMenu   = in_array(admin('uid'), explode(',', config('administrator'))) ? $this->getAdminMenu($module) : $this->getAuthMenu($module);
+        // 菜单树形
+        $adminMenu    = list_to_tree($adminMenu, 'id', 'pid', 'children', 0);
+       
+        // 分配数据
+        $this->assign('adminMenu', $adminMenu);
+   
+        // 返回结果
+        return          $adminMenu;
+    }
+
+    /**
+     * 获得管理员菜单
+     * 
+     * */
+    protected function getAdminMenu($module)
+    {
+        // 查询条件
+        $map['type']                        = 'nav';
+        $map['status']                      = '1';
+        if ($module)                        $map['module'] = $module;
+        // 返回菜单数据
+        return                              DB::table('menu')->where($map)->orderBy('sort_order')->get()->toArray();
+    }
+
+    /**
+     * 获得验证菜单
+     * 
+     * */
+    protected function getAuthMenu($module)
+    {
+        // 查询条件
+        $map                                = [];
+        $map[]                              = ['menu.type', '=', 'nav'];
+        $map[]                              = ['menu.status', '=', '1'];
+        if ($module)                        $map[]    = ['menu.module', '=', $module];
+        // 返回菜单数据
+       
+        $menu                               = Db::table('menu')
+        ->join('auth_rule', 'menu.id','=','auth_rule.menu_id')
+        ->where($map)
+        ->whereIn('auth_rule.group_id',admin('group_id'))
+        ->orderBy('menu.sort_order')
+        ->orderBy('menu.id')->groupBy('menu.id')->select(['menu.id','menu.pid','menu.module','menu.title','menu.url','menu.icon'])->get()->toArray();
+     
+        return                              $menu;
+    }
+
+
+    
+
+}

+ 201 - 0
app/Http/Controllers/Admin/AuthManager.php

@@ -0,0 +1,201 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\AuthManager as Request;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 权限管理
+ * 
+ * @author    刘相欣
+ *
+ */
+class AuthManager extends Auth{
+	
+	/**
+	 * 初始化
+	 * 
+	 * */
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','系统');
+		$this->assign('breadcrumb2','权限管理');
+	}
+	
+	/**
+	 * 初始化
+	 * 
+	 * */
+    public function index(){
+  		// 查询列表数据
+     	$list = DB::table('auth_group')->select()->paginate(config('page_num',10))->appends(request()->all());
+		// 分配数据
+		$this->assign('list',$list);
+		// 加载模板
+    	return $this->fetch();
+	}
+
+	/**
+	 * 新增
+	 * 
+	 * */
+	public function add(Request $request){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收参数
+			$data['title']			= request('title','');
+			$data['description']	= request('description','');
+			$data['group_pid']		= request('group_pid',0);
+			// 返回结果
+			$result					= DB::table('auth_group')->insert($data);
+			// 如果状态停用
+			if( !$result )			return json_send(['code'=>'error','msg'=>'添加失败']);
+			// 结果
+			return json_send(['code'=>'success','msg'=>'添加成功','action'=>'add']);
+		}
+		// 查询用户组
+		$group						= DB::table('auth_group')->whereNotIn('id',explode(',',config('CUSTOM_GROUP')))->select(['id','title'])->get()->toArray();
+		// 错误告知
+		if( !$group )				$this->error('请先添加用户组');
+		$this->assign('crumbs','新增');
+		$this->assign('group',$group);
+		return $this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit(Request $request){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收参数
+			$id						= request('id',0);
+			$data['title']			= request('title','');
+			$data['description']	= request('description','');
+			$data['group_pid']		= request('group_pid',0);
+			// 返回结果
+			$result					= DB::table('auth_group')->where(['id'=>$id])->update($data);
+			// 如果状态停用
+			if( !$result )			return json_send(['code'=>'error','msg'=>'编辑失败']);
+			// 结果
+			return json_send(['code'=>'success','msg'=>'编辑成功','action'=>'edit']);
+		}
+		$group = DB::table('auth_group')->find((int)request('id'));
+
+		$merge_group = explode(',',config('CUSTOM_GROUP'));
+		array_push($merge_group,$group['id']);
+		//dd($merge_group);
+		// 查询用户组
+		$groups						= DB::table('auth_group')->where(['group_pid'=>0])->whereNotIn('id',$merge_group)->select(['id','title'])->get()->toArray();
+		// 错误告知
+		if( !$groups )				$this->error('请先添加用户组');
+		$this->assign('group',$group);
+		$this->assign('crumbs','编辑');
+		$this->assign('groups',$groups	);
+		return $this->fetch();		
+	}
+	
+	/**
+	 * 删除
+	 * 
+	 * */
+	public function del(Request $request){
+		// 验证参数
+		$request->scene('del')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		// 执行删除
+		$result			= DB::table('auth_group')->delete($id);
+		// 错误告知
+		if( !$result )	return json_send(['code'=>'error','msg'=>'删除失败']);
+		// 结果
+		return json_send(['code'=>'success','msg'=>'删除成功']);
+	}
+
+	/**
+	 * 授权
+	 * 
+	 * */
+	public function access(Request $request){
+		// 验证参数
+		$request->scene('del')->validate();
+		// 如果是post
+		if(request()->isMethod('post')){
+			// 接收参数
+		 	$data['rules']			= (array) request('rules',[]);
+			// 权限组Id
+			$group_id				= (int) request('id',0);
+			// 删除权限
+			DB::table('auth_rule')->where(['group_id'=>$group_id])->delete();
+			// 存在权限
+		 	if( isset($data['rules']) ){
+		 		// 排序
+	            sort($data['rules']);
+				// 切割
+	            $data['rules']  = implode( ',' , array_unique($data['rules']));
+	        }
+			// 修改权限
+			$result 			= DB::table('auth_group')->where(['id'=>$group_id])->update($data);
+			// 告知结果
+			if( !$result ) 		return	json_send(['code'=>'success','msg'=>'权限组修改失败','action'=>'edit']);
+			// 权限组菜单
+			$group_menu			= DB::table('auth_group')->find($group_id);
+			// 菜单ID
+			$menu_id			= explode(',', $group_menu['rules']);
+			// 获得菜单列表
+			$menu_list			= DB::table('menu')->get()->toArray();
+			// 循环菜单ID
+			foreach ($menu_id as $v) {
+				// 循环菜单列表
+				foreach ($menu_list as $v1) {
+					// 如果对应的菜单
+					if( $v == $v1['id'] ){
+						// 组合菜单权限数据
+						$m['menu_id']	= $v;
+						$m['group_id']	= $group_id;
+						$m['name']		= !empty($v1['url']) ? $v1['url'] : '';
+						// 写入菜单权限规则表
+						DB::table('auth_rule')->insert($m);
+					}
+				}					
+			}
+			// 告知结果
+			return json_send(['code'=>'success','msg'=>'编辑成功','action'=>'edit']);
+		}
+		// 接收参数
+		$id			= request('id',0);
+		// 获取菜单
+		$menu		= DB::table('menu')->orderBy('sort_order')->get()->toArray();
+		// 获取规则
+		$rules		= DB::table('auth_group')->select('rules')->find($id);
+		// 树形
+		$menu		= array_sort(list_to_tree($menu,'id','pid','child',0),'module',SORT_ASC);
+		// 权限菜单
+		$this->assign('access_menu',$menu);
+		// 规则
+		$this->assign('rules',$rules);
+		// 加载模板
+		return $this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status(Request $request){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 执行删除
+		$result			= DB::table('auth_group')->where(['id'=>$id])->update(['status'=>$status]);
+		// 错误告知
+		if( !$result )	return json_send(['code'=>'error','msg'=>'操作失败','path'=>'']);
+		// 结果
+		return			json_send(['code'=>'success','msg'=>'操作成功','path'=>'']);
+	}
+}
+?>

+ 144 - 0
app/Http/Controllers/Admin/Banner.php

@@ -0,0 +1,144 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Banner as Request;
+use App\Models\Banner as Model;
+use App\Models\City;
+
+/**
+ * banner管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Banner extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','营销管理');
+		$this->assign('breadcrumb2','首页轮播');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 接受参数
+		$name					= request('name','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','=',$name];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['thumb']		= $value['thumb'] ? path_compat($value['thumb']) : '';
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,City $City){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['link_url']		= request('link_url','');
+			$cityIds				= request('city_ids',[]);
+			$data['city_ids']		= implode(',',$cityIds);
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 获取列表
+		$cityList					= $City->getCityList();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('cityList',$cityList);
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,City $City){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['link_url']		= request('link_url','');
+			$cityIds				= request('city_ids',[]);
+			$data['city_ids']		= implode(',',$cityIds);
+			// 如果没有选择,则意味着全部
+			$cityIds				= $cityIds ? $cityIds : [1];
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 获取城市ID
+		$oldData['city_ids']		= explode(',',$oldData['city_ids']);
+		// 获取列表
+		$cityList					= $City->getCityList();
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('cityList',$cityList);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 145 - 0
app/Http/Controllers/Admin/Business.php

@@ -0,0 +1,145 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Business as Request;
+use App\Models\Business as Model;
+use Illuminate\Support\Carbon;
+
+/**
+ * 商业公司管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Business extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','商家管理');
+		$this->assign('breadcrumb2','商业公司');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model){
+ 		// 接受参数
+		$code					= request('business_code','');
+		$phone					= request('phone','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 编码转ID
+		$id						= $Model->codeToId($code);
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['id','=',$id];
+		if( $phone )			$map[] = ['phone','=',$phone];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['business_code'] = $Model->idToCode($value['id']);
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			$data['name']			= request('name','');
+			$data['phone']			= request('phone','');
+			$data['logopic']		= request('logopic','');
+			$data['desc']			= request('desc','');
+			// 写入数据表
+			$id						= $Model->add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询用户
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['name']			= request('name','');
+			$data['phone']			= request('phone','');
+			$data['logopic']		= request('logopic','');
+			$data['desc']			= request('desc','');
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$id				= request('uid',0);
+		$status			= request('status',0);
+		// 查询用户
+		$oldData		= $Model->where(['uid'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status]);		
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 66 - 0
app/Http/Controllers/Admin/Config.php

@@ -0,0 +1,66 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Config as Model;
+
+/**
+ * 地区管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Config extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','系统');
+		$this->assign('breadcrumb2','基础配置');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 超管可以管理所有
+		$map 			= in_array(admin('uid'), explode(',', config('administrator'))) ? [] : [['is_settings','=','1']];
+ 		// 查询用户
+		$list			= $Model->query()->where($map)->paginate(config('page_num',10))->appends(request()->all());
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 			$this->fetch();
+    }
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Model $Model){
+		// 接受参数
+		$id						= request('id',0);
+		// 查询数据
+		$oldData				= $Model->query()->find($id);
+		// 修改
+		if(request()->isMethod('post')){
+			// 组合数据
+			$data['value']		= request('value','');
+			// 写入
+			$result				= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )		return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,$data);
+			// 告知结果
+			return				json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 如果是没有数据
+		if( !$oldData )			return $this->error('查无数据');
+		// 分配数据
+		$this->assign('crumbs','修改'.$oldData['info']);
+		$this->assign('oldData',$oldData);
+		// 加载模板
+		return					$this->fetch(); 
+	}
+
+}

+ 205 - 0
app/Http/Controllers/Admin/ContactWay.php

@@ -0,0 +1,205 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Work\State as Model;
+use App\Facades\Servers\WechatWork\ContactWay as Work;
+use App\Facades\Servers\WechatWork\User as WorkUser;
+use App\Facades\Servers\WechatWork\CorpTag as WorkTag;
+use App\Http\Requests\Admin\ContactWay as Request;
+use App\Models\Custom;
+
+/**
+ * 联系方式-联系我
+ *
+ * @author    刘相欣
+ *
+ */
+class ContactWay extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','联系方式');
+		$this->assign('breadcrumb2','渠道活码');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Custom $Custom){
+ 		// 接受参数
+		$user					= request('user','');
+		$remark					= request('remark','');
+		$customUid				= request('customUid','');
+		// 查询条件
+		$map 					= [];
+		// 组合条件
+		if( $remark )			$map[] = ['remark','LIKE','%'.$remark.'%'];
+		if( $user )				$map[] = ['user','LIKE','%'.$user.'%'];
+		if( $customUid )		$map[] = ['custom_uid','=',$customUid];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 接待成员
+			$value['user'] 		= explode(',',$value['user']);
+			// 标签信息
+			$value['tags'] 		= explode(',',$value['tags']);
+			// 使用对象
+			$value['custom_name'] = $Custom->getValue($value['custom_uid'],'username');
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 获取部门数据
+		$partUserList 			= WorkUser::getListDepart();
+		// 获取标签数据
+		$corpTagList			= WorkTag::getList();
+		// 获取商业与地区代表
+		$customList				= $Custom->getListUserType();
+		// 分配数据
+		$this->assign('list',$list);
+		$this->assign('partUserList',$partUserList);
+		$this->assign('customList',$customList);
+		$this->assign('corpTagList',$corpTagList);
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model,Custom $Custom){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 状态
+			$state['remark']		= request('remark','');
+			$state['user_type']		= request('user_type','');
+			$state['custom_uid']	= request('custom_uid',0);
+			$state['tags']			= request('tags',[]);
+			$state['user']			= request('user',[]);
+			// 数据处理
+			$state['tags']			= implode(',',$state['tags']);
+			$state['user']			= implode(',',$state['user']);
+			// 获取ID
+			$id						= $Model->add($state);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'参数创建失败','path'=>'']);
+			// 接收数据
+			$data['user']			= request('user',[]);
+			$data['remark']			= request('remark','');
+			$data['state']			= http_build_query(['state_id'=>$id]);
+			// 写入数据表
+			$data					= Work::add($data,2,2);
+			// 如果操作失败
+			if( !$data ) 			return json_send(['code'=>'error','msg'=>'活码创建失败','path'=>'']);
+			// 写入数据表
+			$result					= $Model->edit($id,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'活码创建失败','path'=>'']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 获取部门数据
+		$partUserList 				= WorkUser::getListDepart();
+		// 获取标签数据
+		$corpTagList				= WorkTag::getList();
+		// 获取商业与地区代表
+		$customList					= $Custom->getListUserType();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('partUserList',$partUserList);
+		$this->assign('corpTagList',$corpTagList);
+		$this->assign('customList',$customList);
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model,Custom $Custom){
+		// 接收数据
+		$id							= request('id','');
+		// 获取旧数据
+		$oldData					= $Model->getOne($id);
+		// 修改
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 如果操作失败
+			if( !$oldData ) 		return json_send(['code'=>'error','msg'=>'数据不存在','path'=>'']);
+			// 状态
+			$state['remark']		= request('remark','');
+			$state['user_type']		= request('user_type','');
+			$state['custom_uid']	= request('custom_uid',0);
+			$state['tags']			= request('tags',[]);
+			$state['user']			= request('user',[]);
+			// 数据处理
+			$state['tags']			= implode(',',$state['tags']);
+			$state['user']			= implode(',',$state['user']);
+			// 接收数据
+			$data['user']			= request('user',[]);
+			$data['remark']			= request('remark','');
+			// 写入数据表
+			$result					= Work::edit($oldData['config_id'],$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'活码编辑失败','path'=>'']);
+			// 写入数据表
+			$result					= $Model->edit($id,$state);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'活码编辑失败','path'=>'']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'编辑成功','action'=>'edit']);
+		}
+		// 如果不存在的话
+		if( !$oldData )				return $this->error('数据未查到');
+		// 标签切割
+		$oldData['tags']			= explode(',',$oldData['tags']);
+		// 接待人员切割
+		$oldData['user']			= explode(',',$oldData['user']);
+		// 获取部门数据
+		$partUserList 				= WorkUser::getListDepart();
+		// 获取标签数据
+		$corpTagList				= WorkTag::getList();
+		// 获取商业与地区代表
+		$customList					= $Custom->getListUserType();
+		// 分配数据
+		$this->assign('crumbs','修改');
+		$this->assign('oldData',$oldData);
+		$this->assign('customList',$customList);
+		$this->assign('corpTagList',$corpTagList);
+		$this->assign('partUserList',$partUserList);
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+
+	/**
+	 * 设置为客服推送
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function set_follow(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_follow')->validate();
+		// 接收参数
+		$id								= request('id',0);
+		// 如果需要默认当前的话
+		$Model->query()->where([])->update(['is_follow'=>0]);
+		// 查询是否已经提交过
+		$result							= $Model->edit($id,['is_follow'=>1]);
+		// 提示
+		if( !$result )					return json_send(['code'=>'error','msg'=>'设置失败,请重试','data'=>['error'=>'写入失败']]);
+		// 二维码
+		$Model->getFollowQrcode(true);
+		// 记录行为
+		// $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['is_follow'=>1]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 181 - 0
app/Http/Controllers/Admin/CorpTag.php

@@ -0,0 +1,181 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Facades\Servers\WechatWork\CorpTag as Work;
+
+/**
+ * 企业标签
+ *
+ * @author    刘相欣
+ *
+ */
+class CorpTag extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','企业标签');
+		$this->assign('breadcrumb2','标签管理');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(){
+		// 查询数据
+		$list					= Work::getList();
+		// 分配数据
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(){
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$data['group_name']		= request('group_name','');
+			$data['order']			= request('order','');
+			$tag					= request('tag',[]);
+			// 如果不存在标签
+			if( empty($tag['name']) ) return json_send(['code'=>'error','msg'=>'至少添加一个标签']);
+			// 增加一个
+			$data['tag']			= [$tag];
+			// 写入数据表
+			$id						= Work::add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增分组');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function edit(){
+		// 接收数据
+		$id							= request('id','');
+		// 修改
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$name					= request('name','');
+			$order					= request('order',0);
+			// 写入数据表
+			$id						= Work::edit($id,$name,$order);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+	
+
+
+
+
+	/**
+	 * 删除
+	 * 
+	 * */
+	public function del(){
+		// 接收参数
+		$groupId					= request('group_id','');
+		$tagId						= request('tag_id','');
+		// 指定IP
+		$groupIds					= $groupId ? [$groupId] : [];
+		$tagIds						= $tagId ? [$tagId] : [];
+		// 写入数据表
+		$id							= Work::del($tagIds,$groupIds);
+		// 如果操作失败
+		if( !$id ) 					return json_send(['code'=>'error','msg'=>'删除失败']);
+		// 告知结果
+		return						json_send(['code'=>'success','msg'=>'删除成功','path'=>'']);
+	}
+
+
+
+	/**
+	 * 标签列表
+	 * 
+	 * */
+    public function tags(){
+		// 接收参数
+		$groupId				= request('group_id','');
+		// 指定IP
+		$groupIds				= $groupId ? [$groupId] : [];
+		// 查询数据
+		$list					= Work::getList([],$groupIds);
+		// 分配数据
+		$this->assign('list',$list);
+		// 分配数据
+		$this->assign('crumbs',request('group_name','').'标签列表');
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+	/**
+	 * 添加标签
+	 * 
+	 * */
+	public function tag_add(){
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$data['group_id']		= request('group_id','');
+			$tag					= request('tag',[]);
+			// 如果不存在标签
+			if( empty($tag['name']) ) return json_send(['code'=>'error','msg'=>'至少添加一个标签']);
+			// 增加一个
+			$data['tag']			= [$tag];
+			// 写入数据表
+			$id						= Work::add($data);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增分组');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 编辑标签
+	 * 
+	 * */
+	public function tag_edit(){
+		// 接收数据
+		$id							= request('id','');
+		// 修改
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$name					= request('name','');
+			$order					= request('order',0);
+			// 写入数据表
+			$id						= Work::edit($id,$name,$order);
+			// 如果操作失败
+			if( !$id ) 				return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+}

+ 420 - 0
app/Http/Controllers/Admin/Coupon.php

@@ -0,0 +1,420 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Coupon as Request;
+use App\Models\AdminUser;
+use App\Models\Coupon as Model;
+use App\Models\CouponProduct;
+use App\Models\CouponRebate;
+use App\Models\Custom;
+use App\Models\CustomCoupon;
+use App\Models\Product;
+use App\Models\FilesManager;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 优惠券管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Coupon extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','营销管理');
+		$this->assign('breadcrumb2','优惠券管理');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser,CustomCoupon $CustomCoupon){
+		// 接受参数
+		$code					= request('coupon_code','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['id','=',$id];
+		if( $startTime )		$map[] = ['start_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['end_time','<=',strtotime($endTime)];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 计算各个优惠券的数量
+		$customTotal			= $CustomCoupon->whereIn('coupon_id',array_column($list->toArray()['data'],'id'))->groupBy('coupon_id')->select([DB::raw('count(*) as total'),'coupon_id'])->pluck('total','coupon_id')->toArray();
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['coupon_code']= $Model->idToCode($value['id']);
+			// id转编号
+			$value['admin_name'] = $AdminUser->getOne($value['admin_uid'],'username');
+			// 过期时间
+			$value['exp_time']	 = $Model->getExpTime($value['exp_time']);
+			// 如果过期时间
+			if( $value['status'] == 0 && ( $value['exp_time']>0 && $value['exp_time']< time() ) ) {
+				// 设置过期状态
+				$Model->setStatusByExpire();
+				// 状态设置
+				$value['status'] =3;
+			}
+			// id转编号
+			$value['custom_total'] = isset($customTotal[$value['id']]) ? $customTotal[$value['id']] : 0;
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,Product $Product,Custom $Custom,FilesManager $FilesManager,CouponRebate $CouponRebate,CustomCoupon $CustomCoupon,CouponProduct $CouponProduct){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name',0);
+			$data['rebate_type']	= request('rebate_type',0);
+			$data['std_pay']		= request('std_pay',0);
+			$data['rebate']			= request('rebate',0);
+			$data['issue_total']	= request('issue_total',0);
+			$data['start_time']		= request('start_time',date('Y-m-d'));
+			$data['end_time'] 		= request('end_time','');
+			$data['type_id']		= request('type_id',1);
+			$data['is_appt']		= request('is_appt',1);
+			// 根据是否上传了商品范围文件
+			if( $data['type_id'] == 1 && !request()->hasFile('product_file') )  return json_send(['code'=>'error','msg'=>'请上传指定商品范围']);
+			// 根据是否上传了客户范围文件
+			if( $data['is_appt'] == 1 && !request()->hasFile('custom_file') )  return json_send(['code'=>'error','msg'=>'请上传指定客户范围']);
+			// 转换时间,默认现在现在生效
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : time();
+			// 转换时间,默认无结束时间
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time'].' 23:59:59') : 0;
+			// 判断有效时间类型。获取不同的过期时间
+			$data['exp_time'] 		= request('exp_type',0) == 1 ? request('exp_days',0) : $data['end_time'];
+			// 赠品ID
+			$rebateId				= 0;
+			// 如果是赠品表的话。处理赠品逻辑
+			if( $data['rebate_type'] == 3 ) {
+				// 产品编码
+				$rebateId 			= $Product->codeToId($data['rebate']);
+				// 赠品ID不存在
+				if( !$rebateId )	return json_send(['code'=>'error','msg'=>'赠品编码格式有误']);
+				// 设置为0,避免数据异常
+				$data['rebate']     = 0;
+			}
+			// 商品范围
+			$products				= [];
+			// 如果是商品范围
+			if( $data['type_id'] == 1 ) {
+				// 读取文件获取指定的商品范围
+				$products 			= $FilesManager->excelToCode(request()->file('product_file'),$Product);
+				// 产品范围不存在
+				if( !$products )	return json_send(['code'=>'error','msg'=>'请上传可用的商品范围']);
+				// 商品数量
+				if( count($products) > 1000 ) return json_send(['code'=>'error','msg'=>'可用的商品范围请勿超过1000']);
+			}
+			// 客户范围
+			$customs				= [];
+			// 如果是客户范围
+			if( $data['is_appt'] == 1 ) {
+				// 读取文件获取指定的客户范围
+				$customs 			= $FilesManager->excelToCode(request()->file('custom_file'),$Custom);
+				// 客户范围不存在
+				if( !$customs )		return json_send(['code'=>'error','msg'=>'请上传可用的客户范围']);
+				// 客户数量
+				if( count($customs) > 10000 ) return json_send(['code'=>'error','msg'=>'客户范围请勿超过10000']);
+			}
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			try {
+				// 写入
+				$id					= $Model->add($data);
+				// 提示新增失败
+				if( !$id )			{
+					// 回滚
+					DB::rollBack();
+					// 提示失败
+					return			json_send(['code'=>'error','msg'=>'新增失败']);
+				}
+				// 当前时间
+				$time 				= time();
+				// 如果有商品范围
+				if( $products )		{
+					// 循环商品
+					foreach ($products as $key => $value) {
+						// 时间处理
+						$value		= ['coupon_id'=>$id,'product_id'=>$value,'insert_time'=>$time,'update_time'=>$time];
+						// 重组
+						$products[$key] = $value;
+					}
+					// 写入数据
+					$result 		= $CouponProduct->insert($products);
+					// 提示新增失败
+					if( !$result )	{
+						// 回滚
+						DB::rollBack();
+						// 提示失败
+						return		json_send(['code'=>'error','msg'=>'商品范围写入失败']);
+					}
+				}
+				// 如果是赠品
+				if( $rebateId )		{
+					// 写入数据
+					$result 		= $CouponRebate->add(['coupon_id'=>$id,'product_id'=>$rebateId,'rebate_num'=>1]);
+					// 提示新增失败
+					if( !$result )	{
+						// 回滚
+						DB::rollBack();
+						// 提示失败
+						return		json_send(['code'=>'error','msg'=>'赠品结果写入失败']);
+					}
+				}
+				// 如果有客户范围
+				if( $customs )		{
+					// 分块,每1000一批写入
+					foreach (array_chunk($customs,1000) as $chunk) {
+						// 循环客户
+						foreach ($chunk as $key => $value) {
+							// 时间处理
+							$value		= ['coupon_id'=>$id,'custom_uid'=>$value,'exp_time'=>$Model->getExpTime($data['exp_time']),'insert_time'=>$time,'update_time'=>$time];
+							// 重组
+							$chunk[$key] = $value;
+						}
+						// 写入数据
+						$result 		= $CustomCoupon->insert($chunk);
+						// 提示新增失败
+						if( !$result )	{
+							// 回滚
+							DB::rollBack();
+							// 提示失败
+							return		json_send(['code'=>'error','msg'=>'客户范围写入失败']);
+						}
+					}
+				}
+				// 提交
+				DB::commit();
+			} catch (\Throwable $th) {
+				// 回滚
+				DB::rollBack();
+				// 提示失败
+				return				json_send(['code'=>'error','msg'=>'内部错误,请重试','data'=>['error'=>$th->getMessage()]]);
+			}
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,Product $Product,Custom $Custom,FilesManager $FilesManager,CouponRebate $CouponRebate,CustomCoupon $CustomCoupon,CouponProduct $CouponProduct){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$data['name']			= request('name',0);
+			$data['rebate_type']	= request('rebate_type',0);
+			$data['std_pay']		= request('std_pay',0);
+			$data['rebate']			= request('rebate',0);
+			$data['issue_total']	= request('issue_total',0);
+			$data['start_time']		= request('start_time',date('Y-m-d'));
+			$data['end_time'] 		= request('end_time','');
+			$data['type_id']		= request('type_id',1);
+			$data['is_appt']		= request('is_appt',1);
+			// 转换时间,默认现在现在生效
+			$data['start_time']		= $data['start_time'] ? strtotime($data['start_time']) : time();
+			// 转换时间,默认无结束时间
+			$data['end_time']		= $data['end_time'] ? strtotime($data['end_time'].' 23:59:59') : 0;
+			// 判断有效时间类型。获取不同的过期时间
+			$data['exp_time'] 		= request('exp_type',0) == 1 ? request('exp_days',0) : $data['end_time'];
+			// 折扣不能超过10
+			if( $data['rebate_type'] == 2 && $data['rebate'] > 9.99 ) return json_send(['code'=>'error','msg'=>'不能设置大于9.99折']);
+			// 赠品ID
+			$rebateId				= 0;
+			// 如果是赠品表的话。处理赠品逻辑
+			if( $data['rebate_type'] == 3 ) {
+				// 产品编码
+				$rebateId 			= $Product->codeToId($data['rebate']);
+				// 赠品ID不存在
+				if( !$rebateId )	return json_send(['code'=>'error','msg'=>'赠品编码格式有误']);
+				// 设置为0,避免数据异常
+				$data['rebate']     = 0;
+			}
+			// 商品范围
+			$products				= [];
+			// 如果是商品范围,并且上传了文件
+			if( $data['type_id'] == 1 && request()->hasFile('product_file')) {
+				// 读取文件获取指定的商品范围
+				$products 			= $FilesManager->excelToCode(request()->file('product_file'),$Product);
+				// 产品范围不存在
+				if( !$products )	return json_send(['code'=>'error','msg'=>'请上传可用的商品范围']);
+				// 商品数量
+				if( count($products) > 1000 ) return json_send(['code'=>'error','msg'=>'可用的商品范围请勿超过1000']);
+			}
+			// 客户范围
+			$customs				= [];
+			// 如果是客户范围,并且上传了文件
+			if( $data['is_appt'] == 1 && request()->hasFile('custom_file') ) {
+				// 读取文件获取指定的客户范围
+				$customs 			= $FilesManager->excelToCode(request()->file('custom_file'),$Custom);
+				// 客户范围不存在
+				if( !$customs )		return json_send(['code'=>'error','msg'=>'请上传可用的客户范围']);
+				// 客户数量
+				if( count($customs) > 10000 ) return json_send(['code'=>'error','msg'=>'客户范围请勿超过10000']);
+			}
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			try {
+				// 写入
+				$result				= $Model->edit($id,$data);
+				// 提示新增失败
+				if( !$result )		{
+					// 回滚
+					DB::rollBack();
+					// 提示失败
+					return			json_send(['code'=>'error','msg'=>'新增失败']);
+				}
+				// 如果是赠品券
+				if( $rebateId )		{
+					// 查询旧的
+					$oldRebateId 		= $CouponRebate->query()->where([['coupon_id','=',$id],['product_id','=',$rebateId]])->value('id');
+					// 如果旧的与新的不一致
+					if(  $oldRebateId != $rebateId ) {
+						// 删除旧的
+						$CouponRebate->query()->where([['coupon_id','=',$id],['product_id','=',$rebateId]])->delete();
+						// 有旧的修改,无则添加新的
+						$result 		= $oldRebateId ? $CouponRebate->edit($oldRebateId,['product_id'=>$rebateId,'rebate_num'=>1]) : $CouponRebate->add(['coupon_id'=>$id,'product_id'=>$rebateId,'rebate_num'=>1]);
+						// 提示新增失败
+						if( !$result )	{
+							// 回滚
+							DB::rollBack();
+							// 提示失败
+							return		json_send(['code'=>'error','msg'=>'赠品结果写入失败']);
+						}
+					}
+				}
+				// 当前时间
+				$time 				= time();
+				// 如果有商品范围
+				if( $products )		{
+					// 循环商品
+					foreach ($products as $key => $value) {
+						// 时间处理
+						$value		= ['coupon_id'=>$id,'product_id'=>$value,'insert_time'=>$time,'update_time'=>$time];
+						// 重组
+						$products[$key] = $value;
+					}
+					// 写入数据
+					$result 		= $CouponProduct->insert($products);
+					// 提示新增失败
+					if( !$result )	{
+						// 回滚
+						DB::rollBack();
+						// 提示失败
+						return		json_send(['code'=>'error','msg'=>'商品范围写入失败']);
+					}
+				}
+				// 如果有客户范围
+				if( $customs )		{
+					// 分块,每1000一批写入
+					foreach (array_chunk($customs,1000) as $chunk) {
+						// 循环客户
+						foreach ($chunk as $key => $value) {
+							// 时间处理
+							$value		= ['coupon_id'=>$id,'custom_uid'=>$value,'exp_time'=>$Model->getExpTime($data['exp_time']),'insert_time'=>$time,'update_time'=>$time];
+							// 重组
+							$chunk[$key] = $value;
+						}
+						// 写入数据
+						$result 		= $CustomCoupon->insert($chunk);
+						// 提示新增失败
+						if( !$result )	{
+							// 回滚
+							DB::rollBack();
+							// 提示失败
+							return		json_send(['code'=>'error','msg'=>'客户范围写入失败']);
+						}
+					}
+				}
+				// 提交
+				DB::commit();
+			} catch (\Throwable $th) {
+				// 回滚
+				DB::rollBack();
+				// 提示失败
+				return				json_send(['code'=>'error','msg'=>'内部错误,请重试','data'=>['error'=>$th->getMessage()]]);
+			}
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 如果是赠品表的话。处理赠品逻辑
+		if( $oldData['rebate_type'] == 3 ) {
+			// 产品编码
+			$rebateId 			= $CouponRebate->getProductByCouponId($oldData['id']);
+			// 产品ID
+			$rebateId 			= isset($rebateId[0]['product_id']) ? $Product->idToCode($rebateId[0]['product_id']) : '';
+			// 设置为0,避免数据异常
+			$oldData['rebate']  = $rebateId;
+		}
+		// 有效期,时间戳或者时间为0表示的时间段,否则表示领取后N天
+		$oldData['exp_type']	= $oldData['exp_time'] > 1000 ? 2 : 1;
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 					$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model,CustomCoupon $CustomCoupon ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 查询数据
+		$result			= $CustomCoupon->setStatusByCouponId($id,$status);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'同步设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 152 - 0
app/Http/Controllers/Admin/Custom.php

@@ -0,0 +1,152 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Custom as Request;
+use App\Models\Custom as Model;
+use App\Models\CustomScore;
+use Illuminate\Support\Carbon;
+
+/**
+ * 客户管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Custom extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','用户管理');
+		$this->assign('breadcrumb2','客户管理');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,CustomScore $CustomScore){
+ 		// 接受参数
+		$code					= request('custom_code','');
+		$phone					= request('phone','');
+		$username				= request('username','');
+		$weibanId				= request('weiban_extid','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 编码转ID
+		$uid					= $Model->codeToId($code);
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $uid )				$map[] = ['uid','=',$uid];
+		if( $phone )			$map[] = ['phone','=',$phone];
+		if( $username )			$map[] = ['username','=',$username];
+		if( $weibanId )			$map[] = ['weiban_extid','=',$weibanId];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('uid')->paginate(config('page_num',10))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['custom_code'] 	= $Model->idToCode($value['uid']);
+			// id转编号
+			$value['custom_score'] 	= $CustomScore->getCustomScore($value['uid']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 						$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 接收数据
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			// 写入数据表
+			$uid					= $Model->add($data);
+			// 如果操作失败
+			if( !$uid ) 			return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+	/**
+	 * 修改
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接收参数
+		$uid						= request('uid',0);
+		// 查询用户
+		$oldData					= $Model->where(['uid'=>$uid])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 接收数据
+			$data['username']		= request('username','');
+			$data['phone']			= request('phone','');
+			// 写入数据表
+			$result					= $Model->edit($uid,$data);
+			// 如果操作失败
+			if( !$result ) 			return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,2,$oldData,$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 产品信息转格式
+		$oldData					= $oldData->toArray();
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 设置状态
+		$uid				= request('uid',0);
+		$status				= request('status',0);
+		// 查询用户
+		$oldData			= $Model->where(['uid'=>$uid])->first();
+		// 如果用户不存在
+		if( !$oldData )		return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 执行修改
+		$result				= $Model->edit($uid,['status'=>$status]);		
+		// 提示新增失败
+		if( !$result )		return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$uid,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 				json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+
+}

+ 154 - 0
app/Http/Controllers/Admin/CustomCompany.php

@@ -0,0 +1,154 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Facades\Servers\WechatWork\ExternalContact;
+use App\Facades\Servers\WechatWork\User as WorkUserServer;
+use App\Http\Requests\Admin\CustomCompany as Request;
+use App\Models\Custom;
+use App\Models\CustomCompany as Model;
+use App\Models\Work\Tag as WorkTag;
+use App\Models\Work\User as WorkUser;
+
+/**
+ * 客户公司资质
+ *
+ * @author    刘相欣
+ *
+ */
+class CustomCompany extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','用户管理');
+		$this->assign('breadcrumb2','客户管理');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Custom $Custom){
+ 		// 接受参数
+		$code					= request('custom_code','');
+		$status					= request('status','0');
+		// 编码转ID
+		$uid					= $Custom->codeToId($code);
+		// 查询条件
+		$map 					= [['status','=',$status]];
+		// 编码ID
+		if( $uid )				$map[] = ['custom_uid','=',$uid];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('insert_time')->paginate(config('page_num',10));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 客户编码
+			$value['custom_code'] = $Custom->idToCode($value['custom_uid']);
+			// 客户编码
+			$value['custom_name'] = $Custom->getValue($value['custom_uid'],'username');
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+	/**
+	 * 修改状态
+	 * 
+	 * */
+	public function set_status(Request $request,Model $Model,Custom $Custom,WorkUser $WorkUser, WorkTag $WorkTag){
+		// 指定客服
+		$id				= request('id',0);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 查询用户的外部联系人
+		$custom			= $Custom->getOne($oldData['custom_uid']);
+		// 返回结果
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('set_status')->validate();
+			// 接收参数
+			$status				= request('status',0);
+			$userids			= request('user',[]);
+			// 如果用户不存在
+			if( !$oldData )		return json_send(['code'=>'error','msg'=>'查无数据']);
+			// 如果用户不存在
+			if( !$custom )		return json_send(['code'=>'error','msg'=>'用户不存在']);
+			// 通过才更新 
+			if( $status == 8 ) {
+				// 如果存在指定客服
+				if( $userids )		{
+					// 查询客服信息
+					$followUsers		= $WorkUser->query()->whereIn('work_userid',$userids)->where([['external_userid','=',$custom['external_userid']]])->get(['id','work_userid','external_userid','remark','remark_company','description'])->toArray();
+					// 如果用户不存在
+					if( !$followUsers )	return json_send(['code'=>'error','msg'=>'没有指定的客服']);
+					// 返回结果
+					$area				= explode('/',$oldData['license_area']);
+					// 处理地区
+					$province			= empty($area[0]) ? '' : $area[0];
+					$city				= empty($area[1]) ? '' : $area[1];
+					// 循环处理
+					foreach ($followUsers as $key => $value) {
+						// 备注修改
+						$value['remark']			= $oldData['remark'];
+						$value['remark_company']	= $oldData['remark_company'];
+						// 打上城市标签
+						$WorkTag->markCityTag($value['work_userid'],$value['external_userid'],$province,$city);
+						// 客户备注
+						ExternalContact::remark($value['external_userid'],$value['work_userid'],['remark'=>$oldData['remark'],'remark_company'=>$oldData['remark_company']]);
+						// 更新客服备注
+						$result 		= $WorkUser->edit($value['id'],$value);
+						// 提示新增失败
+						if( !$result )	return json_send(['code'=>'error','msg'=>'备注修改失败']);
+					}
+				}
+				// 执行修改
+				$result				= $Custom->edit($oldData['custom_uid'],['company_id'=>$id]);
+				// 提示修改失败
+				if( !$result )		return json_send(['code'=>'error','msg'=>'资质设置失败']);
+			}
+			// 执行修改
+			$result				= $Model->edit($id,['status'=>$status,'admin_uid'=>admin('uid')]);
+			// 提示新增失败
+			if( !$result )		return json_send(['code'=>'error','msg'=>'审核失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+			// 告知结果
+			return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+		}
+		// 错误告知
+		if( !$oldData )				return $this->error('查无数据');
+		// 如果没有客户
+		if( !$custom )				return $this->error('用户不存在');
+		// 默认不需要客服
+		$partUserList				= [];
+		// 如果没有的外部联系人ID话
+		if( $custom['external_userid'] ) {
+			// 查询客服信息
+			$followUsers				= $WorkUser->query()->where([['external_userid','=',$custom['external_userid']]])->pluck('work_userid')->toArray();
+			// 获取部门数据
+			$partUserList 				= WorkUserServer::getListDepart();
+			// 循环部门成员
+			foreach ($partUserList as $key=>$part) {
+				// 用户列表
+				foreach ($part['user_list'] as $k=>$user){
+					// 不存在跟进列表的删除
+					if( !in_array($user['userid'],$followUsers) ) unset($part['user_list'][$k]);
+				}
+				// 重组
+				$partUserList[$key]			= $part;
+				// 删除没有跟进人员的部门
+				if( !$part['user_list'] )	unset($partUserList[$key]);
+			}
+		}
+		// 分配数据
+		$this->assign('partUserList',$partUserList);
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return						$this->fetch(); 
+	}
+
+}

+ 104 - 0
app/Http/Controllers/Admin/CustomScore.php

@@ -0,0 +1,104 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\CustomScore as Request;
+use App\Models\Custom;
+use App\Models\CustomScore as Model;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 客户管理
+ *
+ * @author    刘相欣
+ *
+ */
+class CustomScore extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','积分管理');
+		$this->assign('breadcrumb2','客户积分');
+	}
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function incr(Request $request,Model $Model,Custom $Custom){
+		// 接收参数
+		$customUid								= request('custom_uid',0);
+		// 查询数据
+		$custom									= $Custom->getOne($customUid);
+		// 提交
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('incr')->validate();
+			// 接收数据
+			// 接收数据
+			$incrScore							= request('incr_score',0);
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			// 写入数据表
+			$payId								= $Model->trade($customUid,0,$incrScore,4,1);
+			// 如果操作失败
+			if( isset($payId['error']) ) 		{
+				// 回滚
+				DB::rollBack();
+				// 结果提示
+				return 							json_send(['code'=>'error','msg'=>$payId['error']]);
+			}
+			// 提交事务
+			DB::commit();
+			// 告知结果
+			return								json_send(['code'=>'success','msg'=>'增加成功','action'=>'add']);
+		}
+		// 如果不存在
+		if( !$custom )							return $this->error('用户不存在');
+		// 分配数据
+		$this->assign('crumbs','增加积分');
+		$this->assign('custom',$custom);
+		// 加载模板
+		return									$this->fetch(); 
+	}
+
+	/**
+	 * 扣减
+	 * 
+	 * */
+	public function decr(Request $request,Model $Model,Custom $Custom){
+		// 接收参数
+		$customUid								= request('custom_uid',0);
+		// 查询数据
+		$custom									= $Custom->getOne($customUid);
+		// 提交
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('decr')->validate();
+			// 接收数据
+			$decrScore							= request('decr_score',0);
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			// 写入数据表
+			$payId								= $Model->trade($customUid,0,($decrScore*-1),4,2);
+			// 如果操作失败
+			if( isset($payId['error']) ) 		{
+				// 回滚
+				DB::rollBack();
+				// 结果提示
+				return 							json_send(['code'=>'error','msg'=>$payId['error']]);
+			}
+			// 提交事务
+			DB::commit();
+			// 告知结果
+			return								json_send(['code'=>'success','msg'=>'扣减成功','action'=>'add']);
+		}
+		// 如果不存在
+		if( !$custom )							return $this->error('用户不存在');
+		// 分配数据
+		$this->assign('crumbs','扣减积分');
+		$this->assign('custom',$custom);
+		// 加载模板
+		return									$this->fetch(); 
+	}
+
+
+}

+ 32 - 0
app/Http/Controllers/Admin/FilesManager.php

@@ -0,0 +1,32 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\FilesManager as Model;
+use App\Http\Requests\Admin\FilesManager as Request;
+
+/**
+ * 文件管理
+ * 
+ */
+class FilesManager extends Auth{
+
+	/**
+	 * 上传文件
+	 * 
+	 * */
+	public function add( Request $request, Model $FilesManager ){
+		// 如果没有文件
+		if( !$request->hasFile('file') )	return json_send(['code'=>'error','msg'=>'请上传文件']);
+		// 获取表单上传文件 例如上传了001.jpg
+	    $file								= request()->file('file');
+		// 验证文件大小
+		if( $file->getSize() >= 1024*1024*500 ) return json_send(['code'=>'error','msg'=>'文件大小超过500MB']);
+		// 上传数据
+		$result								= $FilesManager->UploadCos($file,$FilesManager);
+		// 移动失败
+		if( isset($result['error']) )		return json_send(['code'=>'error','msg'=>$result['error']]);
+		// 返回结果值
+	    return								json_send(['code'=>'success','msg'=>'上传成功','data'=>$result]);
+	}
+
+}
+?>

+ 317 - 0
app/Http/Controllers/Admin/ImageManager.php

@@ -0,0 +1,317 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use Illuminate\Pagination\LengthAwarePaginator;
+
+/**
+ * 图片管理
+ * 
+ */
+class ImageManager extends Auth{
+
+	//图片保存路径
+	private $upload_url;
+	
+	/* 初始化 */
+	protected function init($uid){
+		// 上传路径
+		$this->upload_url = DIR_IMAGE.'images/'.$uid;
+		// 如果路径不存在,创建
+		if ( !is_dir($this->upload_url) )  mkdir($this->upload_url, 0755,TRUE);
+	}
+	
+	//图片和文件夹展示
+	public function index(){
+		
+		// 初始化
+		$this->init(admin('uid'));
+		// 获取参数
+		$data				= request()->all();
+		// 目录
+		$directory			= isset($data['directory']) ? $data['directory'] : '';
+		//新建文件夹
+		$data['folder_url']	= url('admin/image_manager/folder?'.http_build_query(['directory'=>$directory]));
+		//图片上传
+		$data['upload_url'] = url('admin/image_manager/upload?'.http_build_query(['directory'=>$directory]));
+		//删除
+		$data['delete_url']	= url('admin/image_manager/delete?');
+		//搜索
+		$data['search_url']	= url('admin/image_manager/index?'.http_build_query(['directory'=>$directory]));
+		// 获取数据
+		$file_data			=  $this->get_file_data($data);
+		//dd($file_data);
+		// 图片数据
+		$data['images'] 	= $file_data['images'];
+		$data['pagination'] = $file_data['pagination'];
+		$data['parent'] = $this->get_parent_url($data); 		
+
+		$data['refresh'] =$this->get_refresh_url($data);		
+		
+		$this->assign('data',$data);	
+		$this->assign('heading_title','图片管理器');	
+		return $this->fetch();
+	}
+	
+	public function get_dir($d){
+		$dir='';
+		foreach ($d as $v) {
+				$dir.=$v.'/';
+		}
+		$dir = substr($dir,0,strlen($dir)-1); 
+		return $dir;
+	}
+
+	//图片上传
+	public function upload(){
+		// 初始化
+		$this->init(admin('uid'));
+		// 接收参数
+		$directory						= request('directory','');
+		// 验证是否有这个文件夹
+		$directory						= $directory ? $this->upload_url.'/'.str_replace('-','/', $directory) : $this->upload_url;
+		// Check its a directory
+		if( !is_dir($directory) )  		return ['error'=>'不是一个文件夹'];
+		// 接收文件
+		$files							= request()->file('file');
+		// 循环上传的文件
+		foreach( $files as $file )		{
+			// 仅支持字母数字-_
+			if( !preg_match('/^[A-Za-z0-9\-\_\.]+$/',$file->getClientOriginalName() )) return ['error'=>'仅支持字母数字-_组合'];
+			//保存图片
+			$info						= $file->move($directory,$file->getClientOriginalName());
+			// 如果有错误
+			if( !$info )				return ['error'=>$file->getError()];
+		}
+		// 上传成功
+		return							['success'=>'上传成功'];
+	}
+
+	/**
+	 * 新建文件夹
+	 * 
+	 */
+	public function folder(){
+		// 初始化
+		$this->init(admin('uid'));
+		// 接收参数
+		$directory					= request('directory','');
+		// 要创建的目录名
+		$folder						= request('folder','');
+		// 错误提示
+		if( !$folder )  			return ['error'=>'目录名必填'];
+		// 避免特殊字符
+		$folder						= html_entity_decode($folder, ENT_QUOTES, 'UTF-8');
+		// 仅支持字母数字-_
+		if( !preg_match('/^[A-Za-z0-9\_\.]+$/',$folder) ) return ['error'=>$folder.' 文件夹仅支持字母数字_组合'];
+		// 验证是否有这个文件夹
+		$directory					= $directory ? $this->upload_url.'/'.str_replace('-','/', $directory) : $this->upload_url.'/';
+		// 替换上级目录
+		$folder 					= str_replace(['../', '..\\', '..'],'',$folder,$count);
+		// 有上级目录
+		if( $count )				return ['error'=>'不支持创建上级目录'];
+		// 不允许多级
+		if( count(explode('/',$folder)) > 1 )  return ['error'=>'不支持直接创建多级目录'];
+		// 替换上一级
+		$folder						= '/' . trim($folder,'/').'/';
+		// 拼接路径
+		$folder						= $directory . $folder;
+		// 如果路径不存在,创建
+		if ( is_dir($folder) )  	return ['error'=>'目录已存在'];
+		// 创建文件夹
+		mkdir($folder, 0755, TRUE);
+		// 创建成功
+		return						['success'=>'创建成功'];
+	}
+
+
+	//删除图片和文件夹
+	public function delete(){
+		// 初始化
+		$this->init(admin('uid'));
+		// 接收参数
+		$paths				= request('path',[]);
+		// 没有要删除的文件夹
+		if( !$paths )		return ['success'=>'非法操作'];
+		// 删除
+		foreach ($paths as $key => $value) {
+			// 替换路径
+			$value 			= str_replace('-','/', $value);
+			// 判断是否增加路径
+			$paths[$key] 	= is_dir($value) ? $value : DIR_IMAGE.$value;
+		}
+		// 调用删除
+		$this->deleteFolderAndFile($paths);
+		// 清除缓存
+		$this->deleteFolderAndFile([DIR_IMAGE.'cache/images/']);
+		// 删除成功
+		return				['success'=>'删除成功'];
+	}
+
+	/**
+	 * 删除文件夹以及文件
+	 * 
+	 * @param  $paths  路径
+	 * 
+	 */
+	private function deleteFolderAndFile($paths){
+		//	循环处理
+		foreach ($paths as $value) {
+			// 替换掉前后路径
+			$value			= str_replace(['../', '..\\', '..'],'', $value);
+			// 替换成斜杠路径
+			$value			= str_replace('-','/', $value);
+			// 拼接路径
+			$value			= $value;
+			// 判断是文件么
+			if( is_file($value) ){
+				// 文件直接删除
+				unlink($value);
+			}else{
+					// 如果是目录
+				$files = [];
+				// Make path into an array
+				$path = [$value];
+				// While the path array is still populated keep looping through
+				while (count($path) != 0) {
+					$next = array_shift($path);
+					foreach ( glob($next) as $file) {
+						// If directory add to path array
+						if ( is_dir($file) ) $path[] = $file . '/*';
+						// Add the file to the files to be deleted array
+						$files[] = $file;
+					}
+				}
+				// Reverse sort the file array
+				rsort($files);
+				foreach ($files as $file) {
+					// If file just delete
+					if (is_file($file)) {
+						@unlink($file);
+					// If directory use the remove directory function
+					} elseif (is_dir($file)) {
+						@rmdir($file);
+					}
+				}
+			}
+		}
+		// 返回结果
+		return  ['success'=>'删除成功'];
+	}
+
+
+	//取得上一级的链接
+	public function get_parent_url($data){
+		$url = [];
+		if (isset($data['directory'])) {
+			// 验证是否有这个文件夹
+			$d						= explode('-', $data['directory'] );
+			$dir					= '';
+			if(count($d)>1){
+				for ($i=0; $i <(count($d)-1); $i++) {
+					if($i<(count($d)-2)){
+						$dir.=$d[$i].'-';
+					}else{
+						$dir.=$d[$i];
+					}
+				}
+				$url['directory']=$dir;
+			}			
+		}
+		if (isset($data['target'])) {
+			$url['target']=$data['target'];
+		}
+
+		if (isset($data['thumb'])) {
+			$url['thumb'] =$data['thumb'];
+		}	
+		return url('admin/image_manager/index?'.http_build_query($url));
+	}
+	
+	//取得刷新的链接(重新加载当前页面的数据)
+	public function get_refresh_url($data){
+		$url = [];
+		if (isset($data['directory'])) {			
+			$url['directory']=$data['directory'];			
+		}
+		if (isset($data['target'])) {
+			$url['target']=$data['target'];
+		}
+		if (isset($data['thumb'])) {
+			$url['thumb'] =$data['thumb'];
+		}
+		return url('admin/image_manager/index?'.http_build_query($url));
+	}
+
+	//取得图片文件,文件夹数据,分页数据
+	public function get_file_data($data){
+//		判断是不是有搜索名称
+		$filter_name			= isset($data['filter_name']) ? rtrim(str_replace(['../', '..\\', '..', '*'], '', $data['filter_name']), '/') : null;
+//		验证是否有这个文件夹
+		$directory				= empty( $data['directory'] ) ? $this->upload_url : $this->upload_url.'/'.str_replace('-','/', $data['directory']);
+//		取得文件夹
+		$directories			= (array) glob($directory . '/' . $filter_name . '*', GLOB_ONLYDIR);
+//		取得文件
+		$files 					= (array) glob($directory . '/' . $filter_name . '*.{jpg,jpeg,png,gif,JPG,JPEG,PNG,GIF}', GLOB_BRACE);
+//		合并文件夹和文件
+		$images					= array_merge($directories, $files);
+//		如果没有文件或文件夹
+		if( empty($images) ) 	return ['images'=>null,'pagination'=>null];
+		if( isset($images['error']) ) return ['images'=>null,'pagination'=>null,'error'=>$images['error']];
+		// 如果没有文件或文件夹
+		if( !$images )			return ['images'=>null,'pagination'=>null];
+		//分页用链接
+		$url 								= [];
+		if ( isset($data['directory']) ) 	$url['directory']	= $data['directory'];
+		if ( isset($data['filter_name']) )  $url['filter_name'] = html_entity_decode($data['filter_name'], ENT_QUOTES, 'UTF-8');
+		if ( isset($data['target']) )		$url['target']		= $data['target'];
+		if ( isset($data['thumb']) ) 		$url['thumb']		= $data['thumb'];
+		// 分页
+		$pagination				= new LengthAwarePaginator( array_slice($images,(16*(request('page')?request('page')-1:0)),16) ,count($images),16,null,['path'=>url('admin/image_manager/index?'.http_build_query($url))]);
+		// 图片
+		$images					= $pagination->items();
+		// 循环所有目录及文件
+		foreach ($images as $image) {
+			// 获取文件名
+			$name				= basename($image);
+			// 获取后缀
+			$ext				= pathinfo($image,PATHINFO_EXTENSION);
+			// 临时数据
+			$temp				= [];
+			$thumb		= mb_substr($image, mb_strlen(DIR_IMAGE),mb_strlen($image));
+			//echo ($thumb);
+			// 如果是图片显示
+			if( in_array($ext,['jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF']) ){
+				// 组合参数
+				//$temp['thumb']			= path_compat($thumb, 100, 100);
+				$temp['thumb']			= $thumb;
+				$temp['name']			= $name;
+				$temp['type']			= 'image';
+				$temp['path']			= $thumb;
+				// 赋值
+				$result['images'][]		= $temp;
+			}
+			// 如果没有后缀,是目录
+			if( !$ext ){
+				// url跳转时的目录
+				$url['directory']		= rtrim(str_ireplace('/', '-', mb_substr($image, mb_strlen($this->upload_url.'/'),mb_strlen($image))),'-');
+				// 显示时的目录
+				$path					= str_ireplace('/', '-', $image);
+				// 打开
+				if ( isset($data['target']) )	$url['target']	= $data['target'];
+				// 缩略
+				if (isset($data['thumb']))  	$url['thumb']	= $data['thumb'];
+				// 组合参数
+				$temp['thumb']			= '';
+				$temp['name']			= $name;
+				$temp['type']			= 'directory';
+				$temp['path']			= $path;
+				$temp['href']			= url('admin/image_manager/index?'.http_build_query($url));
+				// 赋值
+				$result['images'][]		= $temp;
+			}
+		}
+		//分页显示
+		$result['pagination']			= $pagination->render();
+		//返回列表数据
+		return							$result;
+	}
+}

+ 48 - 0
app/Http/Controllers/Admin/Index.php

@@ -0,0 +1,48 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use Illuminate\Support\Facades\Cache;
+
+/**
+ * 后台控制器
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Index extends Auth{
+	
+	
+    public function index()
+    {
+		
+        // 获取菜单
+        $this->getMenu('admin');
+		// 请求结果
+        return      $this->fetch();
+    }
+
+    /**
+	 * 欢迎页
+	 * 
+	 * */
+	public function welcome()
+	{
+	   
+		// 加载模板
+		return $this->fetch();
+	}
+
+
+    /**
+	 * 清理缓存
+	 * 
+	 * */
+	public function refresh()
+	{
+		
+        // 清除缓存
+        Cache::flush();
+		// 加载模板
+		return      json_send(['code'=>'success','msg'=>'刷新成功']);
+	}
+
+}

+ 94 - 0
app/Http/Controllers/Admin/Login.php

@@ -0,0 +1,94 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\AdminUser;
+use App\Servers\Tencent\Sms;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 管理后台登录控制器
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Login extends Admin {
+
+	/**
+	 * 登录方法
+	 * 
+	 * */
+	public function index(AdminUser $AdminUser){
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$username						= request('username','');
+			// 接收数据
+			$code							= request('code','');
+			// 验证
+			if( !$username || !$code )		return json_send(['code'=>'error','msg'=>'用户名验证码必填']);
+			// 查询用户
+			$uid							= $AdminUser->orWhere('username',$username)->orWhere('phone',$username)->value('uid');
+			// 获取数据
+			$admin							= $AdminUser->getOne($uid);
+			// 用户不存在
+			if( !$admin || $admin['status'] ) return json_send(['code'=>'error','msg'=>'用户名不存在或已被停用']);
+			// 比对密码
+			if( md5($code) != $admin['password'] ) return json_send(['code'=>'error','msg'=>'密码错误或账号不存在']);
+			// 查询用户的组别
+			$group							= DB::table('auth_group_access')->where(['user_uid'=>$admin['uid']])->pluck('group_id')->toArray();
+			// 权限小组
+			$admin['group_id']				= $group;
+			// 删除敏感数据-密码
+			unset($admin['password']);
+			// 存储登录状态
+			session(['userAuth'=>$admin]);
+			// 表单令牌
+			return							json_send(['code'=>'success','msg'=>'登录成功','path'=>url('admin')]);
+		}
+		// 加载模板
+		return								$this->fetch();
+	}
+
+	/**
+	 * 退出登录方法
+	 * 
+	 * */
+	public function out(){
+		// 清除
+		session()->flush();
+		// 跳转
+		return								$this->error('退出成功',url('admin/login/index'));
+	}
+
+	/**
+	 * 发送验证码
+	 * 
+	 * */
+	public function send_code(Sms $Sms){
+		if( request()->isMethod('post') ){
+			// 接收数据
+			$username						= request('username','');
+			// 如果有数据,并且短信验证码时间未过时
+			if( !$username )				return json_send(['code'=>'error','msg'=>'用户名必填']);
+			// 获取数据
+			$session						= session('validSmsCode');
+			// 如果有数据,并且验证码创建的时间在一分钟之内
+			if( $session && time() - $session['create_time'] < 60 ) return json_send(['code'=>'error','msg'=>'请稍后再试']);
+			// 查询用户
+			$admin							= DB::table('admin')->orWhere('username',$username)->orWhere('phone',$username)->first(['uid','username','phone','status']);
+			// 用户不存在
+			if( !$admin || $admin['status']) return json_send(['code'=>'error','msg'=>'用户名不存在或已被停用']);
+			// 生成验证码
+			$code 							= strval(rand(100000,999999));
+			// 调用验证码发送
+			$result							= $Sms->send($admin['phone'],$code);
+			// 如果失败
+			if( isset($result['error']) )	return json_send(['code'=>'error','msg'=>$result['error']]);
+			// session数据
+			$session 						= ['code'=>$code,'phone'=>$admin['phone'],'create_time'=>time()];
+			// 存入session
+			session(['validSmsCode'=>$session]);
+			// 成功结果
+			return							json_send(['code'=>'success','msg'=>'发送成功']);
+		}
+	}
+
+}

+ 96 - 0
app/Http/Controllers/Admin/Menu.php

@@ -0,0 +1,96 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Menu as AdminMenu;
+use Illuminate\Support\Facades\DB;
+/**
+ * 菜单管理
+ *
+ * @author    刘相欣
+ */
+class Menu extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','系统');
+		$this->assign('breadcrumb2','后台菜单管理');
+	}
+
+	/**
+	 * 列表 
+	 */
+    public function index(){
+		$cate 		=	DB::table('menu')->select(['id','pid','module','title as name'])->get()->toArray();
+		// 树形
+		$list		= array_sort(list_to_tree($cate),'module',SORT_ASC);
+		$this->assign('list',json_encode($list,TRUE));
+		return	$this->fetch();
+    }
+	
+	public function add(AdminMenu $request){
+		// 进行验证
+		$request->scene('add')->validate();
+		// 接收参数
+		$data['pid']		= (int) request('id',0);
+		$data['sort_order']	= (int) request('sort_order',0);
+		$data['title']		= request('title','');
+		$data['url']		= request('url','');
+		$data['module']		= request('module','');
+		$data['icon']		= request('icon','');
+		$data['type']		= request('type','');
+		// 新增
+		$id					= DB::table('menu')->insertGetId($data);
+		// 提示
+		if( !$id )			return ['error'=>'新增失败'];
+		// 成功
+		return				['success'=>'添加成功','id'=>$id,'name'=>$data['title']];
+	}
+
+	/* 编辑 */
+	public function edit(AdminMenu $request){
+		// 进行验证
+		$request->scene('edit')->validate();
+		// 接收参数
+		$id					= (int) request('id',0);
+		$data['sort_order']	= (int) request('sort_order',0);
+		$data['title']		= request('title','');
+		$data['url']		= request('url','');
+		$data['module']		= request('module','');
+		$data['icon']		= request('icon','');
+		$data['type']		= request('type','');
+		// 新增
+		$result				= DB::table('menu')->where(['id'=>$id])->update($data);
+		// 提示
+		if( !$result )		return ['error'=>'编辑失败'];
+		// 成功
+		return				['success'=>'修改成功','name'=>$data['title']];
+	}
+
+	/* 删除 */
+	public function del(AdminMenu $request){
+		// 进行验证
+		$request->scene('del')->validate();
+		// 接收参数
+		$id				= (int) request('id');
+		// 如果有数据
+		if(DB::table('menu')->where(['pid'=>$id])->first()) return ['error'=>'请先删除子节点!!'];
+		// 删除节点
+		$result 		= DB::table('menu')->where('id',$id)->delete();
+		// 删除失败
+		if( !$result )  return ['error'=>'请先删除子节点!!'];
+		// 删除成功
+		return			['success'=>'删除成功'];
+	}
+
+	/* 获取信息 */
+	public function get_info(AdminMenu $request){
+		// 进行验证
+		$request->scene('get_info')->validate();
+		// 接收参数
+		$id				= (int) request('id');
+		// 查询数据
+		$data			= DB::table('menu')->find($id);
+		// 返回结果
+		return			$data;
+	}
+
+}

+ 395 - 0
app/Http/Controllers/Admin/Orders.php

@@ -0,0 +1,395 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Orders as Request;
+use App\Models\Custom;
+use App\Models\FilesManager;
+use App\Models\Product;
+use App\Models\Orders as Model;
+use App\Models\OrdersAddr;
+use App\Models\OrdersProduct;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Border;
+use PhpOffice\PhpSpreadsheet\Style\Color;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
+
+/**
+ * 订单管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Orders extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','销售管理');
+		$this->assign('breadcrumb2','订单管理');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,OrdersProduct $OrdersProduct,Product $Product,Custom $Custom){
+		// 接受参数
+		$code					= request('order_code','');
+		$productCode			= request('product_code','');
+		$customCode				= request('custom_code','');
+		$productName			= request('product_name','');
+		$status					= request('status',0);
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$productId				= $productCode ? $Product->codeToId($productCode) : 0;
+		$uid					= $customCode ? $Custom->codeToId($customCode) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['orders_product.order_id','=',$id];
+		if( $uid )				$map[] = ['custom.uid','=',$uid];
+		if( $productId )		$map[] = ['orders_product.product_id','=',$productId];
+		if( $productName )		$map[] = ['orders_product.product_name','=',$productName];
+		if( $startTime )		$map[] = ['orders_product.insert_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['orders_product.insert_time','<=',strtotime($endTime)];
+		if( $status )			$map[] = ['orders_product.status','=',$status];
+		// 查询数据
+		$list					= $OrdersProduct->query()
+									->join('custom','orders_product.custom_uid','=','custom.uid')
+									->join('orders_addr','orders_addr.order_id','=','orders_product.order_id')
+									->where($map)
+									->orderByDesc('id')
+									->select([
+										'orders_product.*','custom.username as custom_name',
+										'orders_addr.contact_name','orders_addr.contact_phone','orders_addr.contact_province','orders_addr.contact_city','orders_addr.contact_area','orders_addr.contact_addr'
+									])
+									->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['order_code']	= $Model->idToCode($value['order_id']);
+			$value['state']			= $Model->getState($value['status'],'state');
+			$value['product_code']	= $Product->idToCode($value['product_id']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return						$this->fetch();
+    }
+
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 获取产品和数量
+		$oldData 		= $Model->query()->find($id);
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'订单不存在']);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+	
+
+	/**
+	 * 表格导入
+	 * 
+	 * */
+	public function import_execl( Request $request,Model $Model,Custom $Custom,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct, FilesManager $FilesManager){
+		// 验证参数
+		$request->scene('import_execl')->validate();
+		// 获取表格信息
+		$file								= request()->file('order_file');
+		// 返回结果
+		$sheetList							= $FilesManager->excelToOrder($file);
+		// 如果不存在结果
+		if( isset($sheetList['error']) )	return json_send(['code'=>'error','msg'=>$sheetList['error']]);
+		// 订单列表
+		$orderList							= [];
+		// 当前时间
+		$time								= time();
+		// 循环表格数据
+		foreach ($sheetList as $value) {
+			// 状态更改
+			$value['status']				= $Model->getWeibanStatus($value['status']);
+			// 客户手机号
+			$orderList[$value['weizan_orderid']]['custom']				= ['phone'=>$value['contact_phone'],'username'=>$value['buyer_nick']];
+			// 组合成订单的收件地址
+			$orderList[$value['weizan_orderid']]['contact']				= [
+																			'contact_name'=>$value['contact_name'],
+																			'contact_phone'=>$value['contact_phone'],
+																			'contact_province'=>$value['contact_province'],
+																			'contact_city'=>$value['contact_city'],
+																			'contact_area'=>$value['contact_area'],
+																			'contact_addr'=>$value['contact_addr']
+																		];
+			
+			// 组合成订单的收件地址
+			$orderList[$value['weizan_orderid']]['product'][]			= [
+																			'status'=>$value['status'],
+																			'product_name'=>$value['product_name'],
+																			'sku_attr_names'=>$value['sku_attr_names'],
+																			'buy_num'=>$value['buy_num'],
+																			'pay_total'=>$value['pay_total'],
+																			'price_total'=>$value['pay_total'],
+																			'insert_time'=>$value['insert_time'],
+																			'update_time'=>$time,
+																		];
+			// 组合成订单的需要的数据
+			if( !isset($orderList[$value['weizan_orderid']]['order']) )	$orderList[$value['weizan_orderid']]['order'] = ['weizan_orderid'=>$value['weizan_orderid'],'status'=>$value['status'],'pay_total'=>0,'price_total'=>0,'insert_time'=>$value['insert_time']];
+			// 价格
+			$orderList[$value['weizan_orderid']]['order']['pay_total']  = $orderList[$value['weizan_orderid']]['order']['pay_total'] + $value['pay_total'];
+			$orderList[$value['weizan_orderid']]['order']['price_total']  = $orderList[$value['weizan_orderid']]['order']['pay_total'];
+		}
+		// 新增地址
+		$newAddrList						= [];
+		// 要更新的订单子表
+		$orderProduct						= [];
+		// 循环订单列表
+		foreach ($orderList as $value) 		{
+			// 获取手机号,查询是否用客户
+			$custom							= $Custom->getOneByPhone($value['custom']['phone']);
+			// 如果存在手机号
+			$uid							= $custom ? $custom['uid'] : $Custom->add($value['custom']);
+			// 如果客户存在
+			if( !$uid )						return json_send(['code'=>'error','msg'=>$value['custom']['username'].'【'.$value['custom']['phone'].'】'.'无法创建用户']);
+			// 通过订单号查询是否存在系统订单
+			$orderId						= $Model->query()->where([['weizan_orderid','=',$value['order']['weizan_orderid']]])->value('id');
+			// 客户ID
+			$value['order']['custom_uid'] 	= $uid;
+			// 存在订单获取订单ID,不存在则新增
+			$orderId						= $orderId ? $Model->edit($orderId,$value['order']) : $Model->add($value['order']);
+			// 如果客户存在
+			if( !$orderId )					return json_send(['code'=>'error','msg'=>$orderId.'订单写入失败']);
+			// 订单库
+			$addrId							= $OrdersAddr->query()->where([['order_id','=',$orderId]])->value('id');
+			// 订单ID
+			$value['contact']['order_id']	= $orderId;
+			// 订单ID
+			$value['contact']['id'] 		= (int)$addrId;
+			// 不存在地址的话
+			$newAddrList[] 					= $value['contact'];
+			// 循环子订单
+			foreach ( $value['product'] as 	$product ) {
+				// 数据结果
+				$product['order_id']		= $orderId;
+				$product['custom_uid']		= $uid;
+				$product['id']				= (int) $OrdersProduct->query()->where([['order_id','=',$orderId],'product_name'=>$product['product_name'],'sku_attr_names'=>$product['sku_attr_names']])->value('id');
+				$orderProduct[]				= $product;
+			}
+		}
+		// 新地址写入
+		$OrdersProduct->query()->upsert($orderProduct,'id',['product_name','sku_attr_names','buy_num','pay_total','price_total','update_time']);
+		// 新地址写入
+		$OrdersAddr->query()->upsert($newAddrList,'id',['contact_name','contact_phone','contact_province','contact_city','contact_area','contact_addr']);
+		// 提示成功
+		return								json_send(['code'=>'success','msg'=>'订单导入成功','path'=>'']);
+	}
+
+	/**
+	 * 导出表格导入
+	 * 
+	 * */
+	public function down_excel(Model $Model,OrdersProduct $OrdersProduct,Product $Product,Custom $Custom){
+		// 接受参数
+		$code					= request('order_code','');
+		$productCode			= request('product_code','');
+		$customCode				= request('custom_code','');
+		$productName			= request('product_name','');
+		$status					= request('status',0);
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$productId				= $productCode ? $Product->codeToId($productCode) : 0;
+		$uid					= $customCode ? $Custom->codeToId($customCode) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['orders_product.order_id','=',$id];
+		if( $uid )				$map[] = ['custom.uid','=',$uid];
+		if( $productId )		$map[] = ['orders_product.product_id','=',$productId];
+		if( $productName )		$map[] = ['orders_product.product_name','=',$productName];
+		if( $startTime )		$map[] = ['orders_product.insert_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['orders_product.insert_time','<=',strtotime($endTime)];
+		if( $status )			$map[] = ['orders_product.status','=',$status];
+		// 查询数据
+		$list					= $OrdersProduct->query()
+									->join('custom','orders_product.custom_uid','=','custom.uid')
+									->join('orders_addr','orders_addr.order_id','=','orders_product.order_id')
+									->where($map)
+									->orderByDesc('orders_product.id')
+									->select([
+										'orders_product.id as id','orders_product.order_id','orders_product.custom_uid','orders_product.product_name','orders_product.sku_attr_names as product_spec','orders_product.product_thumb','orders_product.buy_num','orders_product.pay_total','orders_product.status','orders_product.insert_time',
+										'custom.username as custom_name','custom.weiban_extid as weiban_extid',
+										'orders_addr.contact_name','orders_addr.contact_phone','orders_addr.contact_province','orders_addr.contact_city','orders_addr.contact_area','orders_addr.contact_addr'
+									])->get()->toArray();
+		// 返回结果
+		$data						= [];
+		// 循环处理数据
+		foreach ($list as $value) {
+			// id转编号
+			$value['order_id']		= $Model->idToCode($value['order_id']);
+			$value['status']		= $Model->getState($value['status'],'state');
+			$value['custom_uid']	= $Custom->idToCode($value['custom_uid']);
+			$value['product_price']	= $value['buy_num'] ? ($value['pay_total'] / $value['buy_num']) : $value['buy_num'];
+			// 重组
+			$data[$value['order_id']]['order_id'] = $value['order_id'];
+			$data[$value['order_id']]['custom_uid'] = $value['custom_uid'];
+			$data[$value['order_id']]['custom_name'] = $value['custom_name'];
+			$data[$value['order_id']]['weiban_extid'] = $value['weiban_extid'];
+			$data[$value['order_id']]['status'] = $value['status'];
+			// 地址
+			$data[$value['order_id']]['contact_name'] = $value['contact_name'];
+			$data[$value['order_id']]['contact_phone'] = $value['contact_phone'];
+			$data[$value['order_id']]['contact_province'] = $value['contact_province'];
+			$data[$value['order_id']]['contact_city'] = $value['contact_city'];
+			$data[$value['order_id']]['contact_area'] = $value['contact_area'];
+			$data[$value['order_id']]['contact_addr'] = $value['contact_addr'];
+			// 子订单
+			$data[$value['order_id']]['product'][] 	  = ['product_name'=>$value['product_name'],'product_spec'=>$value['product_spec'],'product_thumb'=>$value['product_thumb'],'product_price'=>$value['product_price'],'buy_num'=>$value['buy_num'],'pay_total'=>$value['pay_total']];
+		}
+
+		try {
+			// 去下载
+			$this->toDown($data);
+		} catch (\Throwable $th) {
+			dd($th);
+		}
+		
+	}
+
+
+	/**
+	 * 去下载
+	 */
+	private function  toDown($data){
+		// 创建新的电子表格对象
+		$spreadsheet			= new Spreadsheet();
+		// 设置合并单元格的行和列,例如合并A1到B2的单元格
+		$sheet					= $this->setStyle($spreadsheet);
+		// 从第二行写入
+		$row					= 2;
+		// 循环写入
+		foreach ($data as $key => $value) {
+			// 如果有多个商品
+			$count				= count($value['product']);
+			// 如果有多个商品
+			if( $count > 1 )	{
+				// 合并单元格
+				$sheet->mergeCells('A'.$row.':'.'A'.($row+$count-1));
+				$sheet->mergeCells('B'.$row.':'.'B'.($row+$count-1));
+				$sheet->mergeCells('C'.$row.':'.'C'.($row+$count-1));
+				$sheet->mergeCells('D'.$row.':'.'D'.($row+$count-1));
+				$sheet->mergeCells('E'.$row.':'.'E'.($row+$count-1));
+				$sheet->mergeCells('F'.$row.':'.'F'.($row+$count-1));
+				$sheet->mergeCells('G'.$row.':'.'G'.($row+$count-1));
+				$sheet->mergeCells('H'.$row.':'.'H'.($row+$count-1));
+				$sheet->mergeCells('I'.$row.':'.'I'.($row+$count-1));
+				$sheet->mergeCells('J'.$row.':'.'J'.($row+$count-1));
+				$sheet->mergeCells('P'.$row.':'.'P'.($row+$count-1));
+			}
+			// 单元格内容写入
+			$sheet->setCellValue('A'.$row, $value['order_id']);
+			$sheet->setCellValue('B'.$row, $value['custom_uid']);
+			$sheet->setCellValue('C'.$row, $value['custom_name']);
+			$sheet->setCellValue('D'.$row, $value['status']);
+			$sheet->setCellValue('E'.$row, $value['contact_name']);
+			$sheet->setCellValue('F'.$row, $value['contact_phone']);
+			$sheet->setCellValue('G'.$row, $value['contact_province']);
+			$sheet->setCellValue('H'.$row, $value['contact_city']);
+			$sheet->setCellValue('I'.$row, $value['contact_area']);
+			$sheet->setCellValue('J'.$row, $value['contact_addr']);
+			$sheet->setCellValue('P'.$row, $value['weiban_extid']);
+			// 循环产品
+			foreach ($value['product'] as $v) {
+				$sheet->setCellValue('K'.$row, $v['product_name']);
+				$sheet->setCellValue('L'.$row, $v['product_spec']);
+				$sheet->setCellValue('M'.$row, $v['product_price']);
+				$sheet->setCellValue('N'.$row, $v['buy_num']);
+				$sheet->setCellValue('O'.$row, $v['pay_total']);
+				// 函数自增
+				$row++;
+			}
+		}
+		// 
+		// 创建内容
+		$writer 				= IOFactory::createWriter($spreadsheet, 'Xlsx');
+		header('Pragma: public');
+		header('Content-type:application/vnd.ms-excel');
+		header('Content-Disposition: inline;filename=下载订单.xlsx');
+		// 输出数据流
+		return $writer->save('php://output');
+	}
+
+	/**
+	 * 设置表格样式
+	 * 
+	 */
+	private function setStyle(Spreadsheet $spreadsheet){
+		// 选择当前活动的工作表
+		$sheet					= $spreadsheet->getActiveSheet();
+		// 宽
+		$sheet->getColumnDimension('A')->setWidth(15);
+		$sheet->getColumnDimension('B')->setWidth(15);
+		$sheet->getColumnDimension('C')->setWidth(15);
+		$sheet->getColumnDimension('D')->setWidth(15);
+		$sheet->getColumnDimension('E')->setWidth(15);
+		$sheet->getColumnDimension('F')->setWidth(15);
+		$sheet->getColumnDimension('G')->setWidth(15);
+		$sheet->getColumnDimension('H')->setWidth(15);
+		$sheet->getColumnDimension('I')->setWidth(15);
+		$sheet->getColumnDimension('J')->setWidth(50);
+		$sheet->getColumnDimension('K')->setWidth(80);
+		$sheet->getColumnDimension('L')->setWidth(80);
+		$sheet->getColumnDimension('M')->setWidth(10);
+		$sheet->getColumnDimension('N')->setWidth(10);
+		$sheet->getColumnDimension('O')->setWidth(10);
+		$sheet->getColumnDimension('P')->setWidth(50);
+		// 默认高度
+		$sheet->getDefaultRowDimension()->setRowHeight(18);
+		// 加粗第一行
+		$sheet->getStyle('A:P')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setVertical(Alignment::VERTICAL_CENTER);
+		$sheet->getStyle('A1:P1')->getFont()->setBold(true);
+		$sheet->getStyle('A1:P1')->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('FF00FF00'); // ARGB颜色代码,例如绿色
+		// 设置表格标题
+		$sheet
+		->setCellValue('A1', '订单ID')
+		->setCellValue('B1', '客户ID')
+		->setCellValue('C1', '客户昵称')
+		->setCellValue('D1', '订单状态')
+		->setCellValue('E1', '收货人')
+		->setCellValue('F1', '收货人手机号')
+		->setCellValue('G1', '省')
+		->setCellValue('H1', '市')
+		->setCellValue('I1', '区县')
+		->setCellValue('J1', '收货地址')
+		->setCellValue('K1', '产品名称')
+		->setCellValue('L1', '产品规格')
+		->setCellValue('M1', '产品价格')
+		->setCellValue('N1', '产品数量')
+		->setCellValue('O1', '产品金额')
+		->setCellValue('P1', '微伴ID');
+		// 返回结果
+		return 					$sheet;
+	}
+
+}

+ 129 - 0
app/Http/Controllers/Admin/OrdersBanner.php

@@ -0,0 +1,129 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Orders\Banner as Request;
+use App\Models\Orders\Banner as Model;
+
+/**
+ * 产品管理
+ *
+ * @author    刘相欣
+ *
+ */
+class OrdersBanner extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','营销管理');
+		$this->assign('breadcrumb2','下单活动');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 接受参数
+		$name					= request('name','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','=',$name];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['thumb']		= $value['thumb'] ? path_compat($value['thumb']) : '';
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['link_url']		= request('link_url','');
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['link_url']		= request('link_url','');
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 101 - 0
app/Http/Controllers/Admin/OrdersProduct.php

@@ -0,0 +1,101 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\AdminUser;
+use App\Models\Product;
+use App\Models\Orders;
+use App\Models\OrdersProduct as Model;
+use App\Http\Requests\Admin\OrdersProduct as Request;
+
+/**
+ * 订单管理
+ *
+ * @author    刘相欣
+ *
+ */
+class OrdersProduct extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','订单管理');
+		$this->assign('breadcrumb2','订单管理');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser,Product $Product,Orders $Orders){
+		// 接受参数
+		$code					= request('out_code','');
+		$productCode			= request('product_code','');
+		$productCode			= request('product_code','');
+		$productName			= request('product_name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$productId				= $productCode ? $Product->codeToId($productCode) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['orders_product.id','=',$id];
+		if( $productId )		$map[] = ['product.id','=',$productId];
+		if( $productName )		$map[] = ['product.name','=',$productName];
+		if( $startTime )		$map[] = ['orders_product.insert_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['orders_product.insert_time','<=',strtotime($endTime)];
+		if( !is_null($status) )	$map[] = ['orders_product.status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->join('product','orders_product.product_id','=','product.id')
+								->where($map)
+								->orderByDesc('id')
+								->select(['orders_product.*','product.name as product_name'])
+								->paginate(request('limit',config('page_num',10)))
+								->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['out_code']		= $Model->idToCode($value['id']);
+			// id转编号
+			$value['product_code']	= $Product->idToCode($value['product_id']);
+			// id转编号
+			$value['order_code']	= $Orders->idToCode($value['order_id']);
+			// 创建人员
+			$value['admin_name']	= $AdminUser->getOne($value['admin_uid'],'username');
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model,Product $Product){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 获取产品和数量
+		$oldData 		= $Model->query()->find($id,['prouduct_id','buy_num']);
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 如果是取消订单,库存更新
+		if( $status == 4 ) $Product->updateStock($oldData['product_id'],$oldData['buy_num']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 154 - 0
app/Http/Controllers/Admin/OrdersTransport.php

@@ -0,0 +1,154 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\AdminUser;
+use App\Models\Orders;
+use App\Models\Product;
+use App\Models\OrdersProduct;
+use App\Models\OrdersTransport as Model;
+use App\Models\CustomScore;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 订单物流
+ *
+ * @author    刘相欣
+ *
+ */
+class OrdersTransport extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','订单物流');
+		$this->assign('breadcrumb2','物流发货');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser,Orders $Orders){
+		// 接受参数
+		$code					= request('out_code','');
+		$adminName				= request('admin_name','');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$adminId				= $AdminUser->getByName($adminName,'uid');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['orders_transport.id','=',$id];
+		if( $adminId )			$map[] = ['admin_uid','=',$adminId];
+		if( $startTime )		$map[] = ['stock.insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $endTime )			$map[] = ['stock.insert_time','<=',Carbon::createFromFormat('Y-m-d',$endTime)->endOfDay()->getTimestamp()];
+		// 查询数据
+		$list					= $Model->query()->where($map)->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['out_code']		= $Model->idToCode($value['id']);
+			// id转编号
+			$value['order_code']	= $Orders->idToCode($value['order_id']);
+			// 创建人员
+			$value['admin_name']	= $AdminUser->getOne($value['admin_uid'],'username');
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Model $Model,Orders $Orders,OrdersProduct $OrdersProduct,Product $Product,CustomScore $CustomScore){
+		// 获取编码转ID
+		$orderId						= $Orders->codeToId(request('order_code',''));
+		// 客户ID
+		$order							= $Orders->query()->find($orderId,['id','custom_uid','status']);
+		// post添加
+		if( request()->isMethod('post') ){
+			// 提示新增失败
+			if( !$orderId ) 			return json_send(['code'=>'error','msg'=>'请核对订单编码']);
+			// 客户ID
+			$order						= $Orders->query()->find($orderId,['id','custom_uid','status']);
+			// 提示新增失败
+			if( !$order ) 				return json_send(['code'=>'error','msg'=>'订单不存在']);
+			// 转数组
+			$order						= $order->toArray();
+			// 物流编号
+			$data['track_number']		= request('track_number','');
+			$data['order_id']			= $orderId;
+			$data['admin_uid']			= admin('uid');
+			// 组合数据,写入订单表,子表
+			DB::beginTransaction();
+			try {
+				// 写入
+				$id						= $Model->add($data);
+				// 提示新增失败
+				if( !$id )				{
+					// 回滚
+					DB::rollBack();
+					// 添加失败
+					return				json_send(['code'=>'error','msg'=>'新增出库失败']);
+				}
+				// 修改订单状态为已完成
+				$result 				= $Orders->edit($orderId,['status'=>8]);
+				// 提示新增失败
+				if( !$result )			{
+					// 回滚
+					DB::rollBack();
+					// 添加失败
+					return				json_send(['code'=>'error','msg'=>'主订单状态修改失败']);
+				}
+				// 修改为已发货
+				$result 				= $OrdersProduct->query()->where([['order_id','=',$orderId]])->update(['status'=>8,'update_time'=>time()]);
+				// 提示新增失败
+				if( !$result )			{
+					// 回滚
+					DB::rollBack();
+					// 添加失败
+					return				json_send(['code'=>'error','msg'=>'订单状态修改失败']);
+				}
+				// 如果订单的状态是待完成,给客户发放下单积分
+				// if( $order['status'] == 1 )	$CustomScore->trade($order['custom_uid'],$orderId,config('give_orders_score',0),5,1);
+				// 提交事务
+				DB::commit();
+			} catch (\Throwable $th) 	{
+				// 回滚
+				DB::rollBack();
+				// 添加失败
+				return					json_send(['code'=>'error','msg'=>'发货失败','data'=>['error'=>$th->getMessage()]]);
+			}
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'发货成功','action'=>'add']);
+		}
+		// 查询数据
+		$orderList					= $OrdersProduct->query()->where([['order_id','=',$orderId]])->get(['order_id','product_id','buy_num','pay_total','sku_attr_names as product_spec'])->toArray();
+		// 如果有数据的话
+		foreach ($orderList as $key => $value) {
+			// 订单编码
+			$value['product_code']	= $Product->idToCode($value['product_id']);
+			// 订单编码
+			$value['order_code']	= $Orders->idToCode($value['order_id']);
+			// 订单编码
+			$value['product_name']	= $Product->getOne($value['product_id'],'name');
+			// 返回结果
+			$orderList[$key]		= $value;
+		}
+		// 分配数据
+		$this->assign('crumbs','发货');
+		$this->assign('orderList',$orderList);
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+}

+ 528 - 0
app/Http/Controllers/Admin/Product.php

@@ -0,0 +1,528 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Product as Request;
+use App\Models\AdminUser;
+use App\Models\Business;
+use App\Models\City;
+use App\Models\Producer;
+use App\Models\Product as Model;
+use Illuminate\Support\Carbon;
+use App\Models\Product\Spec as ProductSpec;
+use App\Models\Product\Type as ProductType;
+use App\Models\Product\Attr as ProductAttr;
+use App\Models\Product\Skus as ProductSkus;
+use App\Models\Product\City as ProductCity;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 产品管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Product extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','基础信息');
+		$this->assign('breadcrumb2','产品管理');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser,Producer $Producer){
+		// 接受参数
+		$code					= request('product_code','');
+		$name					= request('name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['id','=',$id];
+		if( $name )				$map[] = ['name','like','%'.$name.'%'];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['product_code']	= $Model->idToCode($value['id']);
+			// 创建人
+			$value['admin_name']	= $AdminUser->getOne($value['admin_uid'],'username');
+			// 生产厂家
+			$value['producer_name']	= $Producer->getOne($value['producer_id'],'name');
+			// 重组
+			$list[$key]			  	= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,Producer $Producer,Business $Business,ProductType $ProductType,ProductSpec $ProductSpec,ProductAttr $ProductAttr,ProductSkus $ProductSkus,City $City,ProductCity $ProductCity){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['poster']			= request('poster','');
+			$data['spec']			= request('spec','');
+			$data['price']			= request('price',0);
+			$data['market_price']	= request('market_price',0);
+			$data['producer_id']	= request('producer_id',0);
+			$data['business_id']	= request('business_id',0);
+			$data['stock']			= request('stock',0);
+			$data['admin_uid']		= admin('uid');
+			$description			= request('description','');
+			$attr					= request('attr',[]);
+			$skuList				= request('sku',[]);
+			$cityIds				= request('city_ids',[]);
+			// 如果没有选择,则意味着全部
+			$cityIds				= $cityIds ? $cityIds : [1];
+			// 总库存
+			if( $skuList )			$data['stock'] = array_sum(array_column($skuList,'stock'));
+			// 获取规格属性
+			$specAttr				= $this->getSpecAttr($attr,$ProductSpec,true);
+			// 开启事务
+			DB::beginTransaction();
+			try {
+				// 写入
+				$id						= $Model->add($data);
+				// 提示新增失败
+				if( !$id )				{
+					// 回滚
+					DB::rollBack();
+					// 提示
+					return 				json_send(['code'=>'error','msg'=>'新增失败']);
+				}
+				// 组合数据
+				foreach ($specAttr as $key => $value) {
+					// 查询结果
+					$value['id']		= $ProductAttr->upsertByName($value['name'],$id,$value['spec_id']);
+					// 提示新增失败
+					if( !$value['id'] )	{
+						// 回滚
+						DB::rollBack();
+						// 提示
+						return 			json_send(['code'=>'error','msg'=>'商品属性新增失败']);
+					}
+					// 重组
+					$specAttr[$key]		= $value;
+				}
+				// 循环SKU
+				foreach ($skuList as $attrNames => $value) {
+					// 属性ID值
+					$value['attr_ids']	= [];
+					// 规格属性值组合
+					$value['attr_names']= $attrNames;
+					// 切割成数据
+					$names				= explode(',',$attrNames);
+					// 循环处理
+					foreach ($names as $name) {
+						foreach ($specAttr as $vv) {
+							if( $name == $vv['name'] )  {
+								// 提示新增失败
+								if( !$vv['id'] )	{
+									// 回滚
+									DB::rollBack();
+									// 提示
+									return 			json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
+								}
+								$value['attr_ids'][] = $vv['id'];
+							}
+						}
+					}
+					// 转成好存储的数据
+					$value['attr_ids']	= implode(',',$value['attr_ids']);
+					// 转成好存储的数据
+					$value['product_id']= $id;
+					// 转成好存储的数据
+					$value['insert_time']= time();
+					// 转成好存储的数据
+					$value['update_time']= time();
+					// SKU结果
+					$skuList[$attrNames] = $value;
+				}
+				// 循环城市范围
+				foreach ($cityIds as $key => $value) {
+					// 重组数据
+					$cityIds[$key]		= ['city_id'=>$value,'product_id'=>$id,'insert_time'=>time(),'update_time'=>time()];
+				}
+				// 写入城市范围
+				$ProductCity->query()->insert($cityIds);
+				// 返回结果
+				$result 				= $ProductSkus->insert($skuList);
+				// 提示新增失败
+				if( !$result )			{
+					// 回滚
+					DB::rollBack();
+					// 提示
+					return 				json_send(['code'=>'error','msg'=>'SKU插入失败']);
+				}
+				// 更新内容
+				$Model->updateDesc($id,$description);
+				// 提交
+				DB::commit();
+				// 记录行为
+				$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+				// 告知结果
+				return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+			} catch (\Throwable $th) {
+				// 回滚
+				DB::rollBack();
+				// 提示
+				return 				json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
+			}
+		}
+		// 获取类型数据
+		$typeList				= $ProductType->getList();
+		$cityList				= $City->getCityList();
+		$businessList 			= $Business->getList();
+		$producerList			= $Producer->getList();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('typeList',$typeList);
+		$this->assign('cityList',$cityList);
+		$this->assign('businessList',$businessList);
+		$this->assign('producerList',$producerList);
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,Producer $Producer,Business $Business,ProductType $ProductType,ProductSpec $ProductSpec,ProductAttr $ProductAttr,ProductSkus $ProductSkus,City $City,ProductCity $ProductCity){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['poster']			= request('poster','');
+			$data['spec']			= request('spec','');
+			$data['price']			= request('price',0);
+			$data['market_price']	= request('market_price',0);
+			$data['producer_id']	= request('producer_id',0);
+			$data['business_id']	= request('business_id',0);
+			$data['stock']			= request('stock',0);
+			$description			= request('description','');
+			$attr					= request('attr',[]);
+			$skuList				= request('sku',[]);
+			$cityIds				= request('city_ids',[]);
+			// 如果没有选择,则意味着全部
+			$cityIds				= $cityIds ? $cityIds : [1];
+			// 总库存
+			if( $skuList )			$data['stock'] = array_sum(array_column($skuList,'stock'));
+			// 获取规格属性
+			$specAttr				= $this->getSpecAttr($attr,$ProductSpec,true);
+			// 开启事务
+			DB::beginTransaction();
+			try {
+				// 写入
+				$result					= $Model->edit($id,$data);
+				// 提示新增失败
+				if( !$result )			{
+					// 回滚
+					DB::rollBack();
+					// 提示
+					return 				json_send(['code'=>'error','msg'=>'修改失败']);
+				}
+				// 组合数据
+				foreach ($specAttr as $key => $value) {
+					// 查询结果
+					$value['id']		= $ProductAttr->upsertByName($value['name'],$id,$value['spec_id']);
+					// 提示新增失败
+					if( !$value['id'] )	{
+						// 回滚
+						DB::rollBack();
+						// 提示
+						return 			json_send(['code'=>'error','msg'=>'商品属性新增失败']);
+					}
+					// 重组
+					$specAttr[$key]		= $value;
+				}
+				// 如果不在这个属性列表中的数据删除
+				$ProductAttr->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($specAttr,'id'))->delete();
+				// 循环SKU
+				foreach ($skuList as $attrNames => $value) {
+					// 属性ID值
+					$value['attr_ids']	= [];
+					// 规格属性值组合
+					$value['attr_names']= $attrNames;
+					// 切割成数据
+					$names				= explode(',',$attrNames);
+					// 循环处理
+					foreach ($names as $name) {
+						foreach ($specAttr as $vv) {
+							if( $name == $vv['name'] )  {
+								// 提示新增失败
+								if( !$vv['id'] )	{
+									// 回滚
+									DB::rollBack();
+									// 提示
+									return 			json_send(['code'=>'error','msg'=>'属性SKU匹配失败']);
+								}
+								$value['attr_ids'][] = $vv['id'];
+							}
+						}
+					}
+					// 转成好存储的数据
+					$value['attr_ids']	= implode(',',$value['attr_ids']);
+					// 转成好存储的数据
+					$value['product_id']= $id;
+					// 查询
+					$oldSkuId			= $ProductSkus->query()->where([['product_id','=',$id],['attr_ids','=',$value['attr_ids']]])->value('id');
+					// 判断是否存在ID
+					$value['id']		= $oldSkuId ? $ProductSkus->edit($oldSkuId,$value) : $ProductSkus->add($value);
+					// SKU结果
+					$skuList[$attrNames]= $value;
+				}
+				// 如果不在这个属性列表中的数据删除
+				$ProductSkus->query()->where([['product_id','=',$id]])->whereNotIn('id',array_column($skuList,'id'))->delete();
+				// 获取之前的城市ID
+				$oldCityIds				= $ProductCity->getListByProductId($id);
+				// 循环城市范围
+				foreach ($cityIds as $key => $value) {
+					// 不存在则新增
+					if( !in_array($value,$oldCityIds) ) $ProductCity->add(['city_id'=>$value,'product_id'=>$id]);
+				}
+				// 不存在的城市删除
+				$ProductCity->query()->where([['product_id','=',$id]])->whereNotIn('city_id',$cityIds)->delete();
+				// 更新内容
+				$Model->updateDesc($id,$description);
+				// 提交
+				DB::commit();
+				// 记录行为
+				$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+				// 告知结果
+				return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+			} catch (\Throwable $th) {
+				// 回滚
+				DB::rollBack();
+				// 提示
+				return 				json_send(['code'=>'error','msg'=>'系统异常,写入失败','data'=>$th->getMessage()]);
+			}	
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 产品信息转格式
+		$oldData					= $oldData->toArray();
+		$oldData['description']		= $Model->getDesc($id);
+		$oldData['city_ids']		= $ProductCity->getListByProductId($id);
+		// 获取产品属性
+		$attrList					= $ProductAttr->getListByProductId($id);
+		// 规格属性
+		$specList					= [];
+		// 获取数据
+		foreach ($attrList as $value) {
+			$value['active']		= 0;
+			if( !isset($specList[$value['spec_id']]) ) $specList[$value['spec_id']]		= $ProductSpec->getOne($value['spec_id']);
+			$specList[$value['spec_id']]['attr_list'][]	= $value;
+		}
+		// 产品类型
+		$skuList					= $ProductSkus->getListByProductId($id);
+		// 循环处理
+		foreach ($skuList as $key => $value) {
+			// 数据解析
+			$value['attr_ids']		= explode(',',$value['attr_ids']);
+			// 循环处理
+			foreach ( $value['attr_ids'] as $k=>$attrId ) {
+				// 获取ids对应的name
+				$value['attr_ids'][$k] = $ProductAttr->getValueById($attrId,'name');
+			}
+			// 数据合并
+			$value['attr_ids']		= implode(',',$value['attr_ids']);
+			// 重组
+			$skuList[$key]			= $value;
+		}
+		// 获取类型数据
+		$typeList				= $ProductType->getList();
+		$cityList				= $City->getCityList();
+		$businessList 			= $Business->getList();
+		$producerList			= $Producer->getList();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('typeList',$typeList);
+		$this->assign('cityList',$cityList);
+		$this->assign('businessList',$businessList);
+		$this->assign('producerList',$producerList);
+		$this->assign('oldData',$oldData);
+		$this->assign('skuList',$skuList);
+		$this->assign('specList',$specList);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+
+	/**
+	 * 获取某个类目下的规格
+	 * 
+	 */
+	public function get_spec_html( ProductSpec $ProductSpec){
+		// 接收参数
+		$typeId			= request('type_id',0);
+		// 查询数据
+		$specList		= $ProductSpec->getList();
+		// 循环处理
+		foreach ($specList as $key => $value) {
+			if( $value['type_id'] != $typeId  ) unset($specList[$key]);
+		}
+		// 分配数据
+		$this->assign('specList',$specList);
+		// 加载模板
+		return 			$this->fetch();
+	}
+
+	/**
+	 * 获取某个类目下的规格
+	 * 
+	 */
+	public function get_sku_html( ProductSpec $ProductSpec,ProductSkus $ProductSkus){
+		// 接收参数
+		$attr			= request('attr',[]);
+		$id				= request('product_id',0);
+		// 产品类型
+		$oldSkus		= $id ? $ProductSkus->getListByProductId($id) : [];
+		// 获取规格属性
+		$specAttr		= $this->getSpecAttr($attr,$ProductSpec);
+		// 组合SKU
+		$brushList		= [];
+		// 循环规格属性
+		foreach ($specAttr as $specId => $value) {
+			// 获取SKU组合
+			$brushList[$specId]	= array_column($value['attr_list'],'name');
+		}
+		// sku列表
+		$skuList 		= $this->brush([],$brushList);
+		// 循环规格属性
+		foreach ($skuList as $newKey => $new) {
+			// 获取新数据
+			$new		= ['attr_names'=>$new,'price'=>0,'stock'=>0,'status'=>0];
+			// 循环旧的sku
+			foreach ($oldSkus as $oldKey => $old) {
+				// 如果有相等的规格
+				if( $old['attr_names'] == $new['attr_names']) {
+					$new['price']	= $old['price'];
+					$new['stock']	= $old['stock'];
+					$new['status']	= $old['status'];
+				}
+			}
+			$skuList[$newKey]	= $new;
+		}
+		// 分配数据
+		$this->assign('specAttr',$specAttr);
+		$this->assign('skuList',$skuList);
+		// 加载模板
+		return 			$this->fetch();
+	}
+
+	/**
+	 * 获取规格属性
+	 * @param ProductSpec  $ProductSpec
+	 * 
+	 */
+	private function getSpecAttr($attr,$ProductSpec,$onlyList=false){
+		// 组合参数
+		$specAttr 			= [];
+		// 循环处理数据
+		foreach ($attr as $specId => $value) {
+			$specAttr[$specId]['spec_id']   = $specId;
+			$specAttr[$specId]['spec_name'] = $ProductSpec->getOne($specId,'name');
+			$specAttr[$specId]['attr_list'] = [];
+			foreach ($value['name'] as $key => $name) {
+				// 如果没有名称的,跳过
+				if( !$name )					continue;
+				// 结果
+				$temp 							= ['id'=>0,'spec_id'=>$specId,'thumb'=>'','name'=>'','remark'=>''];
+				// 获取名称
+				$temp['name']  					= $name;
+				// 获取对应的备注信息
+				if( !empty($value['remark'][$key]) ) $temp['remark'] = $value['remark'][$key];
+				if( !empty($value['thumb'][$key]) ) $temp['thumb'] = $value['thumb'][$key];
+				// 获取对应的数据
+				$specAttr[$specId]['attr_list'][]= $temp;
+			}
+			// 没有属性的规格,移除
+			if( !$specAttr[$specId]['attr_list'] )   unset($specAttr[$specId]);
+		}
+		// 仅获取属性列表
+		if( $onlyList ) 	{
+			// 属性列表
+			$attrList							= [];
+			// 判断结果
+			foreach ($specAttr as $value) 		{
+				// 获取数据
+				array_push($attrList,...$value['attr_list']);
+			}
+			// 返回结果
+			$specAttr							= $attrList;
+		}
+		// 返回结果
+		return $specAttr;
+	}
+
+	/**
+	 * 组合SKU
+	 * 
+	 */
+	private function brush($res = [], $arr = []){
+		// 获取第一个规格的属性
+		if (empty($res)) 		$res = (array) array_shift($arr);
+		// 如果只有一个规格,返回该规格的属性即可
+		if (empty($arr)) 		return $res;
+		// 接下来要参与计算的一组属性
+		$current 				= array_shift($arr);
+		// 计算的列表
+		$last 				    = [];
+		// 循环上一次已经算出的集合
+		foreach ($res as $attr) {
+			foreach ($current as $col_val) {
+				$last[] 		= $attr . ',' . $col_val;
+			}
+		}
+		return					$this->brush($last,$arr); # 递归处理, 直到$arr滚到最后一组属性
+	}
+
+}

+ 155 - 0
app/Http/Controllers/Admin/ProductSpec.php

@@ -0,0 +1,155 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Product\Spec as Request;
+use App\Models\Product\Spec as Model;
+use App\Models\Product\Type;
+use Illuminate\Support\Carbon;
+
+/**
+ * 产品管理
+ *
+ * @author    刘相欣
+ *
+ */
+class ProductSpec extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','基础信息');
+		$this->assign('breadcrumb2','产品类型');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,Type $Type){
+		// 接受参数
+		$name					= request('name','');
+		$status					= request('status');
+		$typeId					= request('type_id');
+		$startTime				= request('start_time','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','=',$name];
+		if( $typeId )			$map[] = ['type_id','=',$typeId];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 类型名称
+			$value['type_name'] = $Type->getOne($value['type_id'],'name');
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 获取类型列表
+		$typeList				= $Type->getList();
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		$this->assign('typeList', $typeList);
+		// 加载模板
+		return					$this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,Type $Type){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['type_id']		= request('type_id',0);
+			$data['has_img']		= request('has_img',0);
+			$data['input_type']		= request('input_type',0);
+			// 获取个数
+			$count					= $Model->where([['type_id','=',$data['type_id']]])->count();
+			// 如果超过2个
+			if( $count >= 2 )		return json_send(['code'=>'error','msg'=>'每个类目仅允许两个规格']);
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 获取类型列表
+		$typeList				= $Type->getList();
+		// 分配数据
+		$this->assign('crumbs','新增');
+		$this->assign('typeList', $typeList);
+		// 加载模板
+		return 						$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,Type $Type){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['type_id']		= request('type_id',0);
+			$data['has_img']		= request('has_img',0);
+			$data['input_type']		= request('input_type',0);
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 产品信息转格式
+		$oldData					= $oldData->toArray();
+		// 获取类型列表
+		$typeList					= $Type->getList();
+		// 分配数据
+		$this->assign('crumbs','修改');
+		$this->assign('oldData',$oldData);
+		$this->assign('typeList', $typeList);
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 131 - 0
app/Http/Controllers/Admin/ProductType.php

@@ -0,0 +1,131 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Product\Type as Request;
+use App\Models\Product\Type as Model;
+use Illuminate\Support\Carbon;
+
+/**
+ * 产品管理
+ *
+ * @author    刘相欣
+ *
+ */
+class ProductType extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','基础信息');
+		$this->assign('breadcrumb2','产品类型');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 接受参数
+		$name					= request('name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','=',$name];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 产品信息转格式
+		$oldData					= $oldData->toArray();
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 111 - 0
app/Http/Controllers/Admin/ScoreClockin.php

@@ -0,0 +1,111 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\ScoreClockin as Request;
+use App\Models\Score\Clockin as Model;
+
+
+
+/**
+ * 打卡任务
+ *
+ * @author    刘相欣
+ * 
+ */
+class ScoreClockin extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','任务打卡');
+		$this->assign('breadcrumb2','打卡任务');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 组合查询条件
+		$map			= [];
+		// 查询数据
+		$list			= $Model->where($map)->orderBy('what_day')->orderBy('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();   
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request,Model $Model ){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['what_day']		= (int) request('what_day',0);
+			$data['reward']			= (int) request('reward',0);
+			// 写入用户表
+			$result					= $Model->add($data);
+			// 提示新增失败
+			if( isset($result['error']) ) return json_send(['code'=>'error','msg'=>$result['error']]);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return $this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request,Model $Model ){
+		// 接收参数
+		$id							= request('id',0);
+		// 如果是post
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			$data['what_day']		= (int) request('what_day',0);
+			$data['reward']			= (int) request('reward',0);
+			// 写入用户表
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( isset($result['error']) )		return json_send(['code'=>'error','msg'=>$result['error']]);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData )				return $this->error('查无数据');
+		// 分配数据
+		$this->assign('crumbs','修改');
+		$this->assign('oldData',$oldData);
+		// 加载模板
+		return						$this->fetch();
+	}
+
+	/**
+	 * 删除
+	 * 
+	 * */
+	public function set_status( Request $request,Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status,'update_time'=>time()]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 告知结果
+		return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 96 - 0
app/Http/Controllers/Admin/ScoreOrders.php

@@ -0,0 +1,96 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Score\Orders as Request;
+use App\Models\Custom;
+use App\Models\Score\Product;
+use App\Models\Score\Orders as Model;
+
+/**
+ * 订单管理
+ *
+ * @author    刘相欣
+ *
+ */
+class ScoreOrders extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','积分管理');
+		$this->assign('breadcrumb2','积分订单');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,Product $Product,Custom $Custom){
+		// 接受参数
+		$code					= request('order_code','');
+		$productCode			= request('product_code','');
+		$productName			= request('product_name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$productId				= $productCode ? $Product->codeToId($productCode) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['score_orders.order_id','=',$id];
+		if( $productId )		$map[] = ['score_product.id','=',$productId];
+		if( $productName )		$map[] = ['score_product.name','=',$productName];
+		if( $startTime )		$map[] = ['score_orders.insert_time','>=',strtotime($startTime)];
+		if( $endTime )			$map[] = ['score_orders.insert_time','<=',strtotime($endTime)];
+		if( !is_null($status) )	$map[] = ['score_orders.status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->join('score_product','score_orders.product_id','=','score_product.id')
+									->where($map)
+									->orderByDesc('score_orders.id')
+									->select(['score_orders.*','score_product.name as product_name'])
+									->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['order_code']	= $Model->idToCode($value['id']);
+			$value['state']			= $Model->getState($value['status'],'state');
+			$value['product_code']	= $Product->idToCode($value['product_id']);
+			$value['custom_code']	= $Custom->idToCode($value['custom_uid']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return						$this->fetch();
+    }
+
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model,Product $Product){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 获取产品和数量
+		$oldData 		= $Model->query()->find($id,['prouduct_id','buy_num']);
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'用户不存在']);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 如果是取消订单,库存更新
+		if( $status == 4 ) $Product->updateStock($oldData['product_id'],$oldData['buy_num']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 159 - 0
app/Http/Controllers/Admin/ScoreProduct.php

@@ -0,0 +1,159 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Score\Product as Request;
+use App\Models\AdminUser;
+use App\Models\Score\Product as Model;
+use Illuminate\Support\Carbon;
+
+/**
+ * 积分商品
+ *
+ * @author    刘相欣
+ *
+ */
+class ScoreProduct extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','积分管理');
+		$this->assign('breadcrumb2','积分商品');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser){
+		// 接受参数
+		$code					= request('product_code','');
+		$name					= request('name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['id','=',$id];
+		if( $name )				$map[] = ['name','like','%'.$name.'%'];
+		if( $startTime )		$map[] = ['insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['product_code']	= $Model->idToCode($value['id']);
+			// 创建人
+			$value['admin_name']	= $AdminUser->getOne($value['admin_uid'],'username');
+			// 重组
+			$list[$key]			  	= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['spec']			= request('spec','');
+			$data['stock']			= request('stock',0);
+			$data['score']			= request('score',0);
+			$data['admin_uid']		= admin('uid');
+			$data['status']			= 1;
+			$description			= request('description','');
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 更新内容
+			$Model->updateDesc($id,$description);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			$data['spec']			= request('spec','');
+			$data['stock']			= request('stock',0);
+			$data['score']			= request('score',0);
+			$data['admin_uid']		= admin('uid');
+			$description			= request('description','');
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 更新内容
+			$Model->updateDesc($id,$description);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 产品信息转格式
+		$oldData					= $oldData->toArray();
+		// 获取数据
+		$oldData['description']		= $Model->getDesc($id);
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 186 - 0
app/Http/Controllers/Admin/Stock.php

@@ -0,0 +1,186 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\Stock as Request;
+use App\Models\AdminUser;
+use App\Models\Producer;
+use App\Models\Product;
+use App\Models\Stock as Model;
+use Illuminate\Support\Carbon;
+
+/**
+ * 库存管理
+ *
+ * @author    刘相欣
+ *
+ */
+class Stock extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','库存管理');
+		$this->assign('breadcrumb2','入库管理');
+	}
+
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model,AdminUser $AdminUser,Product $Product,Producer $Producer){
+		// 接受参数
+		$code					= request('enter_code','');
+		$productCode			= request('product_code','');
+		$productName			= request('product_name','');
+		$status					= request('status');
+		$startTime				= request('start_time','');
+		$endTime				= request('end_time','');
+		// 编码转ID
+		$id						= $code ? $Model->codeToId($code) : 0;
+		$productId				= $productCode ? $Product->codeToId($productCode) : 0;
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['stock.id','=',$id];
+		if( $productId )		$map[] = ['product.id','=',$productId];
+		if( $productName )		$map[] = ['product.name','=',$productName];
+		if( $startTime )		$map[] = ['stock.insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $endTime )			$map[] = ['stock.insert_time','<=',Carbon::createFromFormat('Y-m-d',$endTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['stock.status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->join('product','stock.product_id','=','product.id')
+								->where($map)
+								->orderByDesc('id')
+								->select(['stock.*','product.name as product_name','product.spec as product_spec','product.producer_id as producer_id','product.price','product.market_price'])
+								->paginate(request('limit',config('page_num',10)))
+								->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['enter_code']	= $Model->idToCode($value['id']);
+			// id转编号
+			$value['product_code']	= $Product->idToCode($value['product_id']);
+			// 创建人员
+			$value['admin_name']	= $AdminUser->getOne($value['admin_uid'],'username');
+			// 创建人员
+			$value['producer_name']	= $Producer->getOne($value['producer_id'],'name');
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model,Product $Product,Producer $Producer){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['quantity']		= request('quantity',0);
+			$data['produce_batch']	= request('produce_batch','');
+			$data['produce_time']	= request('produce_time','');
+			$data['exp_time']		= request('exp_time','');
+			$data['produce_time']	= strtotime($data['produce_time']);
+			$data['exp_time']		= strtotime($data['exp_time']);
+			$data['product_id']		= $Product->codeToId(request('product_code',''));
+			$data['admin_uid']		= admin('uid');
+			// 提示新增失败
+			if( !$data['product_id'] ) return json_send(['code'=>'error','msg'=>'请核对产品编码']);
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 库存更新
+			$Product->updateStock($data['product_id'],$data['quantity']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 获取编码转ID
+		$productData				= $Product->codeToId(request('product_code',''));
+		// 查询数据
+		$productData				= $productData ? $Product->query()->find($productData,['id','producer_id','price','market_price','spec']) : [];
+		// 如果有数据的话
+		if( $productData )			{
+			// 数据转换
+			$productData			= $productData->toArray();
+			$productData['producer_name'] = $Producer->getOne($productData['producer_id'],'name');
+		}
+		// 分配数据
+		$this->assign('productData',$productData);
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model,Product $Product){
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 修改
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$data['quantity']		= request('quantity',0);
+			$data['produce_batch']	= request('produce_batch','');
+			$data['produce_time']	= request('produce_time','');
+			$data['exp_time']		= request('exp_time','');
+			$data['produce_time']	= strtotime($data['produce_time']);
+			$data['exp_time']		= strtotime($data['exp_time']);
+			$data['product_id']		= $Product->codeToId(request('product_code',''));
+			$data['admin_uid']		= admin('uid');
+			// 提示新增失败
+			if( !$data['product_id'] ) return json_send(['code'=>'error','msg'=>'请核对产品编码']);
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);			
+		}
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 转产品编码
+		$oldData['product_code']	= $Product->idToCode($oldData['product_id']);
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 222 - 0
app/Http/Controllers/Admin/Ueditor.php

@@ -0,0 +1,222 @@
+<?php namespace App\Http\Controllers\Admin;
+
+
+/**
+ * 百度编辑器接口
+ *
+ *
+ * @author    刘相欣
+ *
+ */
+class Ueditor extends Auth
+{
+	protected $config;
+	protected $type;
+	protected $_basepath	= 'uploads/ueditor/';
+
+	/**
+	 * 将内容存到Storage中,返回转存后的文件路径
+	 * 
+	 * @param	String		$action		方法
+	 * @param	String		$ext		后缀
+	 * @param	String		$content	内容
+	 */
+	private function save_storage_content($action,$ext,$content){
+		// 后缀或者内容为空
+		if ( !$ext || !$content )	return ['error'=>'上传内容或者文件格式有误'];
+		// 获得用户路径
+		$user_path					= $this->_get_user_path($action);
+		// 如果不存在目录
+		if( !is_dir($user_path) )	mkdir($user_path,0755,true);
+		// 文件名称
+		$filename					= $user_path.uniqid().'.'. $ext;
+		// 写入数据
+		$result 					= @file_put_contents($filename,$content);
+		// 失败提示
+		if( !$result )				return 	['error'=>'上传失败'];
+		// 返回路径
+		return 						request()->root().'/'.$filename;
+	}
+
+	/**
+	 * 上传
+	 */
+	public function upload()
+	{
+		// 接收参数
+		$this->type			= request('edit_type','');
+		$action				= request('action');
+		// 获取配置
+		$CONFIG				= json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("./static/ueditor/config.json")), true);
+		// 赋值通用
+		$this->config		= $CONFIG;
+		// 判断方法,调用对应方式
+		switch ($action) {
+			case 'config':
+				$result		= response()->json($CONFIG);
+				break;
+				/* 上传图片 */
+			case 'uploadimage':
+				$result = $this->_ueditor_upload(['size' => 1024*1024*100,'ext'=>['jpg', 'gif', 'png', 'jpeg']],'images');
+				break;
+				/* 上传涂鸦 */
+			case 'uploadscrawl':
+				$result = $this->_ueditor_upload_scrawl('scrawl');
+				break;
+				/* 上传视频 */
+			case 'uploadvideo':
+				$result = $this->_ueditor_upload(['size' => 1024*1024*100 ,'ext'=>['mp4', 'avi', 'wmv','rm','rmvb','mkv']],'video');
+				break;
+				/* 上传文件 */
+			case 'uploadfile':
+				$result = $this->_ueditor_upload(['ext'=>['txt','pdf','doc','docx','xls','xlsx','zip','rar','ppt','pptx']],'file');
+				break;
+				/* 列出图片 */
+			case 'listimage':
+				$result = $this->_ueditor_list('images');
+				break;
+				/* 列出文件 */
+			case 'listfile':
+				$result = $this->_ueditor_list('file');
+				break;
+				/* 抓取远程文件 */
+			case 'catchimage':
+				$result = $this->_ueditor_upload_catch();
+				break;
+			default:
+				$result = response()->json(['state'=>'请求地址错误']);
+				break;
+		}
+		// 返回结果
+		return $result;
+	}
+
+	/**
+	 * 编辑列表
+	 * 
+	 * @param	String		$action		方法
+	 * 
+	 * 
+	 * */
+	private function _ueditor_list($action)
+	{
+		// 配置
+		$config					= $this->config;
+		// 判断文件后缀
+		$ext_allow				= $config['imageAllowFiles'];
+		// 默认图片列表长度
+		$listSize				= $this->config['imageManagerListSize'];
+		/* 判断类型 */
+		if( $action == 'file' ) {
+			// 如果是文件
+			$listSize			= $this->config['fileManagerListSize'];
+			// 判断文件后缀
+			$ext_allow			= $config['fileAllowFiles'];
+		}
+		// 允许的文件对象
+		foreach ($ext_allow as $key => $value) {
+			// 去除点
+			$ext_allow[$key] = ltrim($value,'.');
+		}
+		// 合并字符串
+		$ext_allow				= implode(',',$ext_allow);
+		// 列表长度
+		$size					= request('size',$listSize);
+		// 开始
+		$start					= request('start',0);
+		// 获得用户路径
+		$user_path				= $this->_get_user_path($action);
+		// 取得文件
+		$files 					= (array) glob($user_path.'*.{'.$ext_allow.'}', GLOB_BRACE);
+		// 循环处理
+		foreach ($files as $key => $value) {
+			// 组装路径
+			$files[$key]		= request()->root().'/'.$value;
+		}
+		// 总数量
+		$total					= count($files);
+		// 列表数据
+		$list					= array_slice($files,$start,$size);
+		// 返回数据
+		return					response()->json(['state'=>'SUCCESS','list'=>$list,'start'=>$start,'total'=>$total]);
+	}
+
+	/**
+	 * 用户目录
+	 * 
+	 * */
+	private function _get_user_path($action){
+		// 当前登录用户
+		if( admin('uid') )			return $this->_basepath.$action.'/admin/'.admin('uid').'/'.date('Ymd').'/';
+	}
+
+	/**
+	 * 上传
+	 * 
+	 */
+	private function _ueditor_upload($config=[],$action='') {
+		// 如果没有文件
+		if( !$action )							return response()->json(['state'=>'上传方法有误','url'=>'','title'=>'','original'=>'']);		
+		// 如果没有文件
+		if( !request()->hasFile('upfile') )		return response()->json(['state'=>'未接收到文件','url'=>'','title'=>'','original'=>'']);
+		// 本地上传
+		$file									= request()->file('upfile');
+		// 如果没有文件
+		if( !$file->isValid() )					return response()->json(['state'=>'上传错误','url'=>'','title'=>'','original'=>'']);
+		// 配置合并配置
+		if( !empty($config) )					$config = array_merge($this->config,$config);
+		// 获取文件后缀名
+		$ext									= $file->extension();
+		// 获取文件大小
+		$size									= $file->getSize();
+		// 验证文件大小
+		if( isset($config['size']) && $size >= $config['size'] ) 		return response()->json(['state'=>'文件大小超过限制大小','url'=>'','title'=>'','original'=>'']);
+		// 验证文件格式
+		if( isset($config['ext']) && !in_array($ext,$config['ext'] ) )	return response()->json(['state'=>'请上传允许的格式','url'=>'','title'=>'','original'=>'']);
+		// 获取文件名
+		$filename								= ltrim($file->getClientOriginalName(),'/');
+		// 文件名
+		$filename								= html_entity_decode($filename, ENT_QUOTES, 'UTF-8');
+		// 获得用户路径
+		$user_path								= $this->_get_user_path($action);
+		// 保存文件
+		$info									= $file->move($user_path,$filename);
+		// 如果有错误
+		if( !$info )							return ['error'=>$file->getError()];
+		// 移动失败
+		if( isset($objectPath['error']) )		return response()->json(['state'=>$objectPath['error'],'url'=>'','title'=>'','original'=>'']);
+		// 数据
+		$url									= request()->root().'/'.$user_path.$filename;
+		// 状态成功
+		return									response()->json(['state' => 'SUCCESS','url'=>$url,'title'=>$filename,'original'=>$filename]);
+	}
+
+	/**
+	 * 涂鸦
+	 * 
+	 */
+	private function _ueditor_upload_scrawl($action='scrawl'){
+		// 接收数据
+		$data								= request($this->config['scrawlFieldName'],'');
+		// 未接收到涂鸦数据
+		if ( empty ($data) )				return response()->json(['state'=>'涂鸦内容不能为空','url'=>'','title'=>'','original'=>'']);
+		// base64转码接收到的涂鸦数据
+		$img								= base64_decode($data);
+		// 大小
+		$size								= strlen($img);
+		// 验证文件大小
+		if( isset($this->config['scrawlMaxSize']) && $size >= $this->config['scrawlMaxSize'] ) return response()->json(['state'=>'文件大小超过限制大小','url'=>'','title'=>'','original'=>'']);
+		// 调用本地存储方法
+		$savepath							= $this->save_storage_content($action,'png',$img);
+		// 存储失败
+		if ( isset($savepath['error']) )	return response()->json(['state'=>$savepath['error'],'url'=>'','title'=>'','original'=>'']);
+		// 状态成功
+		return								response()->json(['state' => 'SUCCESS','url'=>$savepath,'title'=>'','original'=>'']);
+	}
+
+	//抓取远程文件
+	private function _ueditor_upload_catch(){
+		// 暂不支持
+		return								response()->json(['state' => '暂不支持抓取远程文件','list' => null]);
+	}
+}

+ 64 - 0
app/Http/Controllers/Admin/WeibanExternal.php

@@ -0,0 +1,64 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Models\Custom;
+use App\Models\WeiBan\External as Model;
+use App\Models\WeiBan\Tags as WeiBanTags;
+use Illuminate\Support\Carbon;
+
+/**
+ * 客户管理
+ *
+ * @author    刘相欣
+ *
+ */
+class WeibanExternal extends Auth{
+
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','用户管理');
+		$this->assign('breadcrumb2','微伴客户');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model,Custom $Custom,WeiBanTags $WeiBanTags ){
+ 		// 接受参数
+		$id						= request('id','');
+		$status					= request('status');
+		$name					= request('name');
+		$phone					= request('phone');
+		$remark					= request('remark');
+		$startTime				= request('start_time','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $id )				$map[] = ['weiban_external.id','=',$id];
+		if( $name )				$map[] = ['weiban_external.name','=',$name];
+		if( $phone )			$map[] = ['weiban_follow.phone_number','=',$phone];
+		if( $remark )			$map[] = ['weiban_follow.remark','=',$remark];
+		if( $startTime )		$map[] = ['weiban_external.insert_time','>=',Carbon::createFromFormat('Y-m-d',$startTime)->startOfDay()->getTimestamp()];
+		if( $startTime )		$map[] = ['weiban_external.insert_time','<=',Carbon::createFromFormat('Y-m-d',$startTime)->endOfDay()->getTimestamp()];
+		if( !is_null($status) )	$map[] = ['weiban_external.status','=',$status];
+		// 查询数据
+		$list					= $Model->query()->join('weiban_follow','weiban_follow.weiban_extid','=','weiban_external.id')->where($map)->orderByDesc('insert_time')->paginate(config('page_num',10),['weiban_external.*','weiban_follow.staff_id','weiban_follow.staff_name','weiban_follow.remark','weiban_follow.phone_number'])->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['custom_code'] 	= $value['custom_uid'] ? $Custom->idToCode($value['custom_uid']) : '';
+			// 获取标签
+			$value['tags_list']		= $WeiBanTags->getListByWeibanExtid($value['id']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+
+}

+ 127 - 0
app/Http/Controllers/Admin/WeibanQrcode.php

@@ -0,0 +1,127 @@
+<?php namespace App\Http\Controllers\Admin;
+
+use App\Http\Requests\Admin\WeiBan\Qrcode as Request;
+use App\Models\WeiBan\Qrcode as Model;
+
+/**
+ * 微伴二维码
+ *
+ * @author    刘相欣
+ *
+ */
+class WeibanQrcode extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','客户管理');
+		$this->assign('breadcrumb2','客服二维码');
+	}
+	
+	/**
+	 * 首页列表
+	 * 
+	 * */
+    public function index(Model $Model){
+		// 接受参数
+		$name					= request('name','');
+		// 查询条件
+		$map 					= [];
+		// 编码ID
+		if( $name )				$map[] = ['name','=',$name];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(request('limit',config('page_num',10)))->appends(request()->all());
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// id转编号
+			$value['thumb']		= $value['thumb'] ? path_compat($value['thumb']) : '';
+			// 重组
+			$list[$key]			= $value;
+		}
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list', $list);
+		// 加载模板
+		return $this->fetch();
+    }
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add( Request $request, Model $Model){
+		if( request()->isMethod('post') ){
+			// 验证参数
+			$request->scene('add')->validate();
+			// 组合数据
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			// 写入
+			$id						= $Model->add($data);
+			// 提示新增失败
+			if( !$id )				return json_send(['code'=>'error','msg'=>'新增失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'新增成功','action'=>'add']);
+		}
+		// 分配数据
+		$this->assign('crumbs','新增');
+		// 加载模板
+		return 					$this->fetch();
+	}
+	
+	/**
+	 * 编辑
+	 * 
+	 * */
+	public function edit( Request $request, Model $Model){
+		if(request()->isMethod('post')){
+			// 验证参数
+			$request->scene('edit')->validate();
+			// 组合数据
+			$id						= request('id',0);
+			$data['name']			= request('name','');
+			$data['thumb']			= request('thumb','');
+			// 写入
+			$result					= $Model->edit($id,$data);
+			// 提示新增失败
+			if( !$result )			return json_send(['code'=>'error','msg'=>'修改失败']);
+			// 记录行为
+			$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],$data);
+			// 告知结果
+			return					json_send(['code'=>'success','msg'=>'修改成功','action'=>'edit']);
+		}
+		// 接收参数
+		$id							= request('id',0);
+		// 查询数据
+		$oldData					= $Model->where(['id'=>$id])->first();
+		// 如果是没有数据
+		if( !$oldData ) 			return $this->error('查无数据');
+		// 分配数据
+		$this->assign('oldData',$oldData);
+		$this->assign('crumbs','修改');
+		// 加载模板
+		return 						$this->fetch();
+	}
+
+	/**
+	 * 状态
+	 * 
+	 * */
+	public function set_status( Request $request, Model $Model ){
+		// 验证参数
+		$request->scene('set_status')->validate();
+		// 接收参数
+		$id				= request('id',0);
+		$status			= request('status',0);
+		// 查询数据
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,[],['status'=>$status]);
+		// 告知结果
+		return			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+}

+ 246 - 0
app/Http/Controllers/Admin/WorkSync.php

@@ -0,0 +1,246 @@
+<?php namespace App\Http\Controllers\Admin;
+
+
+use App\Models\Custom;
+use App\Models\Work\Sync as Model;
+use App\Models\Work\Tag as WorkTag;
+use App\Models\Work\User as WorkUser;
+use App\Models\Work\External as WorkExternal;
+use App\Facades\Servers\Redis\RedisLock;
+use App\Facades\Servers\WechatWork\ExternalContact;
+
+/**
+ * 客户同步
+ *
+ * @author    刘相欣
+ *
+ */
+class WorkSync extends Auth{
+	
+	protected function _initialize(){
+		parent::_initialize();
+		$this->assign('breadcrumb1','客户同步');
+		$this->assign('breadcrumb2','同步任务');
+	}
+
+	/**
+	 * 列表页
+	 * 
+	 * */
+    public function index(Model $Model){
+ 		// 接受参数
+		// 查询条件
+		$map 					= [];
+		// 查询数据
+		$list					= $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
+		// 分配数据
+		$this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
+		$this->assign('list',$list);
+		// 加载模板
+		return 					$this->fetch();
+    }
+
+
+	/**
+	 * 添加
+	 * 
+	 * */
+	public function add(Model $Model){
+		// 接收数据
+		$data['cursor']			= request('cursor','');
+		$data['has_total']		= request('has_total',0);
+		$data['sync_total']		= request('sync_total',0);
+		$data['status']			= request('status',0);
+		// 查询是否有进行中的任务
+		$runing					= $Model->query()->where([['status','=',0]])->value('id');
+		// 如果操作失败
+		if( $runing ) 			return json_send(['code'=>'error','msg'=>'请等待任务完成']);
+		// 写入数据表
+		$id						= $Model->add($data);
+		// 如果操作失败
+		if( !$id ) 				return json_send(['code'=>'error','msg'=>'新增失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
+		// 告知结果
+		return					json_send(['code'=>'success','msg'=>'新增成功','path'=>'']);
+	}
+
+	/**
+	 * 仅取消
+	 * 
+	 * */
+	public function set_status(Model $Model){
+		// 设置状态
+		$id				= request('id',0);
+		$status			= request('status',4);
+		// 查询用户
+		$oldData		= $Model->where(['id'=>$id])->first();
+		// 如果用户不存在
+		if( !$oldData )	return json_send(['code'=>'error','msg'=>'任务不存在']);
+		// 执行修改
+		$result			= $Model->edit($id,['status'=>$status]);
+		// 提示新增失败
+		if( !$result )	return json_send(['code'=>'error','msg'=>'设置失败']);
+		// 记录行为
+		$this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
+		// 告知结果
+		return 			json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
+	}
+
+
+	/**
+	 * 执行任务
+	 * 
+	 * */
+	public function run_task(){
+		// 实例
+		$Model					= New Model();
+		// 获取数据
+		$taskList				= $Model->getList();
+		// 如果没有任务列表,结束
+		if( !$taskList )		return ['error'=>'无待执行任务'];
+		// 如果没有任务列表,结束
+		$task					= array_pop($taskList);
+		// 返回结果
+		if( !$task )			return ['error'=>'无待执行任务'];
+		// 异步锁上锁,失败结束
+		if( !RedisLock::lock('work:sync:task:id',$task['id'],'180') ) return ['error'=>'任务执行中...'];
+		// 获取接待人员
+		$userIdList				= ExternalContact::getFollowUsers();
+		// 如果没有成员ID列表,结束
+		if( !$userIdList )		{
+			// 解锁
+			RedisLock::unlock('work:sync:task:id',$task['id']);
+			// 无需同步
+			return  			['error'=>'未获取到跟进人员'];
+		}
+		// 获取游标
+		$cursor					= $task['cursor'];
+		// 批量获取客户详情
+		$extUserList			= ExternalContact::batchGetByUser($userIdList,$cursor,100);
+		// 如果没有客户列表,结束
+		if( !$extUserList )		{
+			// 解锁
+			RedisLock::unlock('work:sync:task:id',$task['id']);
+			// 结束
+			return  			['error'=>'未获取到外部联系人'];
+		}
+		// 实例其他模型
+		$CustomModel			= New Custom();
+		$WorkExternalModel		= New WorkExternal();
+		$WorkUserModel			= New WorkUser();
+		$WorkTagModel			= New WorkTag();
+		// 下一页游标
+		$task['cursor']			= $extUserList['next_cursor'];
+		// 外部联系人列表
+		$extUserList 			= $extUserList['external_contact_list'];
+		// 更新的数据
+		$extUsers				= [];
+		$followUsers			= [];
+		$followTags				= [];
+		// 时间
+		$time 					= time();
+		// 循环处理
+		foreach ( $extUserList as $key=>$value ) {
+			// 外部联系人
+			$extUser						= [];
+			$extUser['name']				= $value['external_contact']['name'];
+			$extUser['avatar']				= str_ireplace('http://','https://',$value['external_contact']['avatar']);
+			$extUser['gender']				= $value['external_contact']['gender'];
+			$extUser['work_type']			= $value['external_contact']['type'];
+			$extUser['external_userid']		= $value['external_contact']['external_userid'];
+			$extUser['insert_time']			= $time;
+			$extUser['update_time']			= $time;
+			// 处理外部联系人
+			$extUsers[] 					= $extUser;
+			// 跟进客服
+			$followUser						= [];
+			$followUser['external_userid']	= $extUser['external_userid'];
+			$followUser['work_userid']		= $value['follow_info']['userid'];
+			$followUser['remark']			= $value['follow_info']['remark'];
+			$followUser['description']		= $value['follow_info']['description'];
+			$followUser['insert_time']		= $time;
+			$followUser['update_time']		= $time;
+			$followUser['remark_mobiles']	= implode(',',$value['follow_info']['remark_mobiles']);
+			$followUser['remark_company']	= empty($value['external_contact']['corp_name'])? (empty($value['follow_info']['remark_corp_name']) ? '' : $value['follow_info']['remark_corp_name']) : $value['external_contact']['corp_name'];
+			$followUsers[]					= $followUser;
+			// 跟进人员标签组合
+			foreach ( $value['follow_info']['tag_id'] as $tagId ) {
+				// 重组
+				$followTags[]				= ['tag_id'=>$tagId,'external_userid'=>$followUser['external_userid'],'work_userid'=>$followUser['work_userid'],'update_time'=>$time];
+			}
+			// 跟进人员是否备注手机号
+			$extUser['phone']				= $value['follow_info']['remark_mobiles'] ? $value['follow_info']['remark_mobiles'][0] : '';
+			// 重组数据
+			$extUserList[$key] 				= $extUser;
+		}
+		// 标签写入
+		if( $followTags )					$WorkTagModel->query()->insert($followTags);
+		// 需要更新的数据
+		$WorkExternalModel->query()->upsert($extUsers,'external_userid',['name','avatar','gender','work_type','update_time']);
+		// 需要更新的数据
+		$WorkUserModel->query()->upsert($followUsers,['external_userid','work_userid'],['remark','description','remark_mobiles','remark_company','update_time']);
+		// 获取外部联系人ID,并去重
+		$customIds							= array_values(array_unique(array_filter(array_column($extUserList,'external_userid'))));
+		// 获取外部联系人ID,并去重
+		$customPhones						= array_values(array_unique(array_filter(array_column($extUserList,'phone'))));
+		// 查询客户表中是否存在该客户
+		$customIds							= $customIds ? $WorkExternalModel->getPluckInFiled('external_userid',$customIds,'custom_uid','external_userid') : [];
+		// 获取
+		$customPhones						= $customPhones ? $CustomModel->getPluckInFiled('phone',$customPhones,'external_userid','phone') : [];
+		// 循环处理
+		foreach ( $extUserList as $value ) {
+			// 不存在外部联系人账号的跳过
+			if( !isset($customIds[$value['external_userid']]) )  continue;
+			// 存在在外部联系人账号但是绑定了账号的跳过
+			if( $customIds[$value['external_userid']] )  		 continue;
+			// 不存在手机号,跳过
+			if( !$value['phone'] )  		 					 continue;
+			// 如果绑定了其他外部联系人
+			if( !empty($customPhones[$value['phone']])  )		 continue;
+			// 同步数量 +1
+			$task['sync_total'] += 1;
+			// 账号UID默认
+			$uid												= 0;
+			// 账号未注册
+			if( !isset($customPhones[$value['phone']]) )		{
+				// 注册账号
+				$uid 											= $CustomModel->add(['phone'=>$value['phone'],'username'=>$value['name'],'userpic'=>$value['avatar'],'sex'=>$value['gender'],'external_userid'=>$value['external_userid']]);
+				// 注册失败,
+				if( !$uid )										continue;
+			}else{
+				// 已经注册的,未绑定外部联系人
+				if( !$customPhones[$value['phone']] )			{
+					// 查询号码
+					$custom										= $CustomModel->getOneByPhone($value['phone']);
+					// 没有账号,跳过
+					if( !$custom )								continue;
+					// 账号存在跳过
+					if( $custom['external_userid'] )			{
+						// 避免重复注册
+						$customPhones[$value['phone']]			= $custom['external_userid'];
+						continue;
+					}
+					// 账号UID
+					$uid										= $custom['uid'];
+				}
+			}
+			// 避免重复注册
+			$customPhones[$value['phone']]						= $value['external_userid'];
+			// 修改
+			$result												= $uid ? $WorkExternalModel->query()->where([['external_userid','=',$value['external_userid']]])->update(['custom_uid'=>$uid,'update_time'=>$time]) : true;
+			// 如果修改失败
+			if( !$result )										continue;
+		}
+		// 如果没有下一页游标,标记任务完成
+		if( !$task['cursor'] )	$task['status'] = 1;
+		// 修改任务情况
+		$Model->edit($task['id'],$task);
+		// 解锁
+		RedisLock::unlock('work:sync:task:id',$task['id']);
+		// 结束
+		return  			['success'=>'批量成功=>'.$task['sync_total']];
+	}
+
+
+}

+ 168 - 0
app/Http/Controllers/Api/Api.php

@@ -0,0 +1,168 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Exceptions\Api\VerifySignException;
+use App\Exceptions\Api\LoginException;
+use App\Facades\Servers\Encrypts\AccessToken;
+use App\Facades\Servers\Encrypts\ApiSign;
+use App\Http\Controllers\Controller;
+use App\Models\Custom;
+
+/**
+ * 接口控制器
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Api extends Controller{
+
+	/**
+	 * 登录验证
+	 * 
+	 * @return	Int			$authcode		登录信息
+	 * 
+	 */
+	public function checkLogin($authcode=''){
+		// 默认接参
+		$authcode											= $authcode ? $authcode : request('authcode','');
+		// 如果没有有登录信息
+		if( !$authcode )									throw new LoginException("please_login");
+		// 解码
+		$decode												= AccessToken::decode($authcode);
+		// 错误返回
+		if( isset($decode['error']) )						throw new LoginException("login_error");
+		// 如果没有过期时间,过期处理
+		if( empty($decode['exp']) )							throw new LoginException("login_exprie");
+		// 如果过期,过期处理
+		if( $decode['exp'] <= time() )						throw new LoginException("login_exprie");
+		// 从缓存获取登录数据
+		$memAuthcode 										= (new Custom())->getLoginAuthCodeByUid($decode['sub']);
+		// 不存在登录信息,提示失败
+		if( !$memAuthcode )									throw new LoginException("login_miss");
+		// 如果是32位的话
+		if( strlen($memAuthcode) == 32 )					$authcode = md5($authcode);
+		// 如果存在登录数据,并且不是当前用户的缓存登录,提示失败
+		if( $authcode != $memAuthcode )						throw new LoginException("login_miss");
+		// 返回用户ID
+		return												$decode['sub'];
+	}
+
+	/**
+	 * 登录验证
+	 * 
+	 * @return	Int		用户ID
+	 * 
+	 */
+	public function getUid($authcode=''){
+		// 默认接参
+		$authcode											= $authcode ? $authcode : request('authcode','');
+		// 如果没有有登录信息
+		if( !$authcode )									return 0;
+		// 尝试执行
+		try {
+			// 解码
+			$decode											= AccessToken::decode($authcode);
+			// 错误返回
+			if( isset($decode['error']) )					return 0;
+			// 如果没有过期时间,过期处理
+			if( empty($decode['exp']) )						return 0;
+			// 如果过期,过期处理
+			if( $decode['exp'] <= time() )					return 0;
+			// 返回用户ID
+			return											$decode['sub'];
+		} catch (\Throwable $th) {
+			// 返回0
+			return											0;
+		}
+	}
+
+	/**
+	 * 接口验签
+	 * 
+	 * @param		[Array]		$data		参与验证的参数
+	 * 
+	 * 
+	 * */
+	public function verify_sign($data=[]){
+		// 获取参数
+		$data									= $data ? $data : request()->all();
+		// 没有签名
+		if( empty($data['sign']) )				throw new VerifySignException('sign_miss');
+		// 没有签名
+		if( empty($data['appid']) )				throw new VerifySignException('appid_miss');
+		// 传了key
+		if( !empty($data['key']) )				throw new VerifySignException('appkey_no_allow');
+		// 没有请求时间
+		if( empty($data['timestamp'])  )        throw new VerifySignException('sign_timeout');
+        // 请求过期
+		if( abs(time() -$data['timestamp'] ) > 86400 ) throw new VerifySignException('sign_timeout');
+        // 已使用过的签名不允许二次使用
+		$this->checkSignUsed($data['sign']);
+		// 从配置读取接口验签应用数据
+		$verify 								= json_decode(config('api_verify'),TRUE);
+		// 是否有对应的appid
+		if( !isset($verify[$data['appid']]) )	throw new VerifySignException('appid_nofund');
+		// appkey
+		$appkey									= $verify[$data['appid']];
+		// 获得签名参数数据
+		$sign									= $data['sign'];
+		// 删除传入签名参数
+		unset($data['sign']);
+		// 删除上传文件的字段
+		if( isset($data['file']))				unset($data['file']);
+		// 键名字典排序
+		ksort($data);
+		// 空字符串
+		$param									= '';
+		// 循环参数对象,拼接url字符串
+		foreach ( $data as $key => $value ) {
+			// 如果键值为空(空字符串 空数组 空集合 空对象 字符串0 数字0 NULL FALSE),此参数省略;另 '000' 这类0组成的字符串 不为空
+			if( strtolower($value)  == 'false' || strtolower($value)  == 'null' || empty($value) || ( is_numeric($value) && $value == 0 && substr_count($value,'.') == 1 ) ) continue;
+			// 判断键值是否是数组,对象 ,如果是的话,键值转json字符串
+			if( is_array( $value ) || is_object($value) ) $value = json_encode($value,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
+			// 如果键值为真则 键值转md5加密(此处小写) 为假则直接拼接,0特殊处理
+			$param  .= '&'.$key.'='.$value;
+		}
+		// 转码
+		$param									= ltrim($param,'&');
+		// 解码
+		$param									= rawurldecode($param);
+		// 拼接私钥数据
+		$param									.= '&key='.$appkey;
+		// 比对签名,数据加密(MD5后转大写),$param.'=>'.strtoupper(md5($param)).'=>'.$sign
+		if( strtoupper(md5($param)) != $sign)	throw new VerifySignException('sign_error');
+		// 验签通过
+		return									['success'=>'验签成功'];
+	}
+
+	/**
+	 * 判断签名是否已用
+	 * 
+	 * @param		[Array]		$data		参与验证的参数
+	 * 
+	 * 
+	 * */
+	public  function checkSignUsed($sign='')	{
+		// 获取签名
+		$is_used								= cache('ApiSign:'.$sign);
+		// 如果签名已用
+		if( $is_used )							throw new VerifySignException('sign_used');
+		// 存储已经验证过的签名
+		cache(['ApiSign:'.$sign=>$sign],60);
+		// 成功返回
+		return									['success'=>'签名可用'];
+	}
+
+	/**
+	 * 接口验签
+	 * 
+	 * @param	Array		$data		参与验证的参数
+	 * 
+	 * 
+	 * */
+	public function sign($data)					{
+		// 返回加密结果
+		return									ApiSign::encode($data);
+	}
+
+
+}

+ 50 - 0
app/Http/Controllers/Api/Banner.php

@@ -0,0 +1,50 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Banner as Model;
+use App\Models\Custom;
+
+/**
+ * 首页Banner
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Banner extends Api{
+	
+	
+	/**
+	 * 获取客户信息			/api/banner/get_list
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_list(Model $Model,Custom $Custom){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->getUid();
+		// 获取客户信息
+		$custom							= $uid ? $Custom->getOne($uid) : [];
+		// 客户的城市ID
+		$cityId							= empty($custom['city_id']) ? 0 : $custom['city_id'];
+		// 查新客户类型
+		$list			                = $Model->getList();
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			//  如果没有限制城市
+			if( !$value['city_ids'] )	continue;
+			// 如果限制了的话,转数组
+			$value['city_ids']			= explode(',',$value['city_ids']);
+			// 判断用户的城市是否在内
+			if( in_array($cityId,$value['city_ids']) )  continue;
+			// 不在范围的删除
+			unset($list[$key]);
+		}
+		// 获取数组格式
+        $list                           = array_values($list);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+	
+}

+ 81 - 0
app/Http/Controllers/Api/Custom.php

@@ -0,0 +1,81 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Custom as Model;
+use App\Models\WeiBan\Qrcode as WeiBanQrcode;
+use Vinkla\Hashids\Facades\Hashids;
+use App\Http\Requests\Api\Custom as Request;
+use App\Models\City;
+
+/**
+ * 客户接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Custom extends Api{
+	
+	
+	/**
+	 * 获取客户信息			/api/custom/get_info
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_info(Model $Model,WeiBanQrcode $WeiBanQrcode){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 查询用户
+		$custom							= $Model->getOne($uid);
+		// 用户不存在
+		if( empty($custom) )			return json_send(['code'=>'error','msg'=>'用户不存在','data'=>['error'=>'用户不存在']]);
+		// 头像
+		$custom['uid']					= Hashids::encodeHex($custom['uid']);
+		// 头像
+		$custom['userpic']				= $custom['userpic'] ? path_compat($custom['userpic']) : '';
+		// 手机号
+		$custom['phone']				= hide_phone($custom['phone']);
+		// 所需数组组合,如果没有关联企微,获取二维码,已添加好友的不验证
+		$custom							= [
+											'uid'=>$custom['uid'],
+											'username'=>$custom['username'],
+											'userpic'=>$custom['userpic'],
+											'phone'=>$custom['phone'],
+											'company_id'=>1, // 无需验证资质
+											'show_price'=>($custom['weiban_extid']?1:0), // 用于判断是否显示价格
+											'city_id'=>$custom['city_id'],
+											'follow_qrcode'=>($custom['weiban_extid'] ? '' : $WeiBanQrcode->getFollowQrcode())
+										];
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$custom]);
+	}
+
+	/**
+	 * 设置信息			/api/custom/set_city
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function set_city(Request $request,Model $Model,City $City){
+		// 接口验签
+		// $this->verify_sign();
+		// 验证参数
+		$request->scene('set_city')->validate();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 接收参数
+		$city							= request('city','');
+		// 通过城市名获取城市ID
+		$cityId							= $City->getIdByName($city);
+		// 查询用户
+		$result							= $Model->edit($uid,['city_id'=>$cityId]);
+		// 用户不存在
+		if( !$result )					return json_send(['code'=>'error','msg'=>'保存失败','data'=>['error'=>'保存失败,请重试']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'保存成功','data'=>['city_id'=>$cityId]]);
+	}
+
+
+}

+ 158 - 0
app/Http/Controllers/Api/CustomAddr.php

@@ -0,0 +1,158 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\CustomAddr as Model;
+use App\Http\Requests\Api\CustomAddr as Request;
+use App\Models\Custom;
+
+/**
+ * 客户地址
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class CustomAddr extends Api{
+	
+
+	/**
+	 * 获取列表			/api/custom_addr/get_list
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_list(Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 查询信息
+		$list							= $Model->getListByCustom($uid);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+	
+	/**
+	 * 添加			/api/custom_addr/add
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 验证参数
+		$request->scene('add')->validate();
+		// 接收参数
+		$data['contact_province']		= request('contact_province','');
+		$data['contact_city']			= request('contact_city','');
+		$data['contact_area']			= request('contact_area','');
+		$data['contact_addr']			= request('contact_addr','');
+		$data['contact_name']			= request('contact_name','');
+		$data['contact_phone']			= request('contact_phone','');
+		$data['is_default']				= request('is_default',0);
+		$data['custom_uid']				= $uid;
+		// 替换地址中间的空格
+		$data['contact_addr']			= str_ireplace(' ','',$data['contact_addr']);
+		// 最大数量
+		$limitMax						= 20;
+		$havaNum						= $Model->query()->where([['custom_uid','=',$uid]])->count();
+		// 如果是最大数量的话
+		if( $havaNum > $limitMax )		return json_send(['code'=>'error','msg'=>'您已经有'.$limitMax.'条地址了','data'=>['error'=>'最多只能保20条地址']]);
+		// 如果需要默认当前的话
+		if( $data['is_default'] )		$Model->query()->where([['custom_uid','=',$uid]])->update(['is_default'=>0]);
+		// 查询是否已经提交过
+		$result							= $Model->add($data);
+		// 如果用户状态被拉黑,不允许登录
+		if( !$result )					return json_send(['code'=>'error','msg'=>'保存失败,请重试','data'=>['error'=>'写入失败']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'保存成功','data'=>$data]);
+	}
+
+
+	/**
+	 * 修改			/api/custom_addr/edit
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 验证参数
+		$request->scene('edit')->validate();
+		// 接收参数
+		$id								= request('id',0);
+		$data['contact_province']		= request('contact_province','');
+		$data['contact_city']			= request('contact_city','');
+		$data['contact_area']			= request('contact_area','');
+		$data['contact_addr']			= request('contact_addr','');
+		$data['contact_name']			= request('contact_name','');
+		$data['contact_phone']			= request('contact_phone','');
+		$data['is_default']				= request('is_default',0);
+		// 替换地址中间的空格
+		$data['contact_addr']			= str_ireplace(' ','',$data['contact_addr']);
+		// 如果需要默认当前的话
+		if( $data['is_default'] )		$Model->query()->where([['custom_uid','=',$uid]])->update(['is_default'=>0]);
+		// 查询是否已经提交过
+		$result							= $Model->edit($id,$data);
+		// 如果用户状态被拉黑,不允许登录
+		if( !$result )					return json_send(['code'=>'error','msg'=>'保存失败,请重试','data'=>['error'=>'写入失败']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'保存成功','data'=>$data]);
+	}
+	
+
+	/**
+	 * 删除			/api/custom_addr/del
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function del(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 验证参数
+		$request->scene('del')->validate();
+		// 接收参数
+		$id								= request('id',0);
+		// 如果需要默认当前的话
+		$result							= $Model->del($id);
+		// 如果用户状态被拉黑,不允许登录
+		if( !$result )					return json_send(['code'=>'success','msg'=>'删除失败','data'=>['error'=>'删除失败']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'删除成功','data'=>['id'=>$id]]);
+	}
+
+	/**
+	 * 修改			/api/custom_addr/set_default
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function set_default(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 验证参数
+		$request->scene('set_default')->validate();
+		// 接收参数
+		$id								= request('id',0);
+		// 如果需要默认当前的话
+		$Model->query()->where([['custom_uid','=',$uid]])->update(['is_default'=>0]);
+		// 查询是否已经提交过
+		$result							= $Model->edit($id,['is_default'=>1]);
+		// 如果用户状态被拉黑,不允许登录
+		if( !$result )					return json_send(['code'=>'error','msg'=>'保存失败,请重试','data'=>['error'=>'写入失败']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'保存成功','data'=>['id'=>$id]]);
+	}
+	
+
+}

+ 87 - 0
app/Http/Controllers/Api/CustomCompany.php

@@ -0,0 +1,87 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\FilesManager;
+use App\Models\CustomCompany as Model;
+use App\Http\Requests\Api\CustomCompany as Request;
+use App\Models\Custom;
+
+/**
+ * 客户资质接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class CustomCompany extends Api{
+	
+	
+	/**
+	 * 获取客户信息			/api/custom_company/apply
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function apply(Request $request,Model $Model,Custom $Custom){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 查新客户类型
+		$custom['user_type']			= (int) $Custom->getValue($uid,'user_type');
+		// 验证参数
+		$request->scene($custom['user_type'] == 2 ? 'repre' : 'custom')->validate();
+		// 用户结果
+		$data['custom_uid']				= $uid;
+		// 接收参数
+		$data['remark']					= request('remark','');
+		$data['remark_company']			= request('remark_company','');
+		$data['license_code']			= request('license_code','');
+		$data['license_name']			= request('license_name','');
+		$data['legal_name']				= request('legal_name','');
+		$data['legal_idcard']			= request('legal_idcard','');
+		$data['license_addr']           = request('license_addr','');
+		// 获取结果
+		$data['license_area']			= [request('province',''),request('city','')];
+		// 存在地区,获取地区
+		if( request('area','') )		$data['license_area'][] = request('area','');
+		// 合并数据
+		$data['license_area']			= implode('/',$data['license_area']);
+		// 查询是否已经提交过
+		$result							= $Model->upsertOne($data);
+		// 如果用户状态被拉黑,不允许登录
+		if( !$result )					return json_send(['code'=>'error','msg'=>'提交失败,请重试','data'=>['error'=>'写入失败']]);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'提交成功','data'=>$data]);
+	}
+	
+
+	/**
+	 * 获取客户资质信息			/api/custom_company/get_info
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_info(Model $Model,Custom $Custom){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 查新客户类型
+		$custom['user_type']			= (int) $Custom->getValue($uid,'user_type');
+		// 查询信息
+		$result							= $Model->getOne($uid);
+		// 如果状态不存在的话
+		if( !$result )					return json_send(['code'=>'success','msg'=>'获取成功','data'=>$custom]);
+		// 返回结果
+		$area							= explode('/',$result['license_area']);
+		// 处理地区
+		$result['province']				= empty($area[0]) ? '' : $area[0];
+		$result['city']					= empty($area[1]) ? '' : $area[1];
+		$result['area']					= empty($area[2]) ? '' : $area[2];
+		$result['user_type']			= $custom['user_type'];
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$result]);
+	}
+
+
+}

+ 142 - 0
app/Http/Controllers/Api/CustomCoupon.php

@@ -0,0 +1,142 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\CouponProduct;
+use App\Models\CouponRebate;
+use App\Models\CustomCoupon as Model;
+
+/**
+ * 客户优惠券接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class CustomCoupon extends Api{
+	
+	
+	/**
+	 * 获取客户优惠券列表			/api/custom_coupon/get_list
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_list(Model $Model,CouponRebate $CouponRebate){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$limit						= request('limit',10);
+		// 显示
+		$map						= [['custom_coupon.custom_uid','=',$uid]];
+		// 查询
+		$Paginator					= $Model->query()->join('coupon','custom_coupon.coupon_id','=','coupon.id')->where($map)->orderBy('custom_coupon.status')->paginate($limit,['custom_coupon.id','coupon.id as coupon_id','coupon.name','coupon.type_id','coupon.rebate_type','coupon.std_pay','coupon.rebate','custom_coupon.status','custom_coupon.exp_time']);
+		// 通过优惠券ID,查询赠品
+		$rebates					= $CouponRebate->getRebatesByCouponIds(array_column($Paginator->items(),'coupon_id'));
+		// 循环处理数据
+		foreach ($Paginator as $key => $value) {
+			$rebateScope			= [];
+			// 获取赠品列表
+			foreach ($rebates as $vv) {
+				// 获取优惠券的赠品
+				if( $vv['coupon_id'] == $value['coupon_id'] ) {
+					unset($vv['coupon_id']);
+					// 赠品信息
+					$rebateScope[] = $vv;
+				}
+			}
+			// 如果过期时间
+			if( $value['status'] == 0 && $value['exp_time'] < time() ) {
+				// 设置过期状态
+				$Model->setStatusByExpire();
+				// 状态设置
+				$value['status'] = 3;
+			}
+			// 适用范围
+			$value['rebate_scope']	= $rebateScope;
+			// 时间
+			$value['exp_time']		= date('Y-m-d H:i:s',$value['exp_time']);
+			// 优惠券回馈类型
+			$value['rebate']		= $value['rebate_type'] == 1 ? $value['rebate'] : intval($value['rebate']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+	/**
+	 * 获取下单可用列表			/api/custom_coupon/get_checked
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_checked(Model $Model,CouponRebate $CouponRebate,CouponProduct $CouponProduct){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 查询条件
+		$map						= [['custom_coupon.custom_uid','=',$uid],['custom_coupon.status','=',0]];
+		// 查询
+		$list						= $Model->query()->join('coupon','custom_coupon.coupon_id','=','coupon.id')->where($map)->orderBy('custom_coupon.status')->get(['custom_coupon.id','coupon.id as coupon_id','coupon.name','coupon.type_id','coupon.rebate_type','coupon.std_pay','coupon.rebate','custom_coupon.status','custom_coupon.exp_time'])->toArray();
+		// 通过优惠券ID,查询商品范围
+		$products					= $CouponProduct->getProductList(array_column($list,'coupon_id'));
+		// 通过优惠券ID,查询赠品
+		$rebates					= $CouponRebate->getRebatesByCouponIds(array_column($list,'coupon_id'));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 适用范围
+			$productScope			= [];
+			// 如果是商品表,获取范围
+			if( $value['type_id'] == 1 ){
+				// 获取适用的商品范围
+				foreach ($products as $vv) {
+					// 获取优惠券指定的商品
+					if( $vv['coupon_id'] == $value['coupon_id'] ) {
+						unset($vv['coupon_id']);
+						$productScope[] = $vv;
+					}
+				}
+			}
+			// 适用范围
+			$value['product_scope']	= $productScope;
+			// 赠品范围
+			$rebateScope			= [];
+			// 获取赠品列表
+			foreach ($rebates as $vv) {
+				// 获取优惠券的赠品
+				if( $vv['coupon_id'] == $value['coupon_id'] ) {
+					unset($vv['coupon_id']);
+					// 赠品信息
+					$rebateScope[] = $vv;
+				}
+			}
+			// 赠品范围
+			$value['rebate_scope']	= $rebateScope;
+			// 如果过期时间
+			if( $value['exp_time'] < time() ) {
+				// 设置过期状态
+				$Model->setStatusByExpire();
+				// 状态设置
+				$value['status'] 	= 3;
+			}
+			// 时间
+			$value['exp_time']		= date('Y-m-d H:i:s',$value['exp_time']);
+			// 优惠券回馈类型
+			$value['rebate']		= $value['rebate_type'] == 1 ? $value['rebate'] : intval($value['rebate']);
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+
+}

+ 72 - 0
app/Http/Controllers/Api/CustomScore.php

@@ -0,0 +1,72 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\CustomScore as Model;
+use App\Models\Orders;
+use App\Models\Score\Record as Record;
+
+
+/**
+ * 客户积分接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class CustomScore extends Api{
+	
+	
+	/**
+	 * 获取积分信息			/api/custom_score/get_info
+	 * 
+	 * */
+	public function get_info(Model $Model,Orders $Orders){
+		// 接口验签
+        // $this->verify_sign();
+		// 验证登录
+        $uid                    		= $this->checkLogin();
+		// 查询数据
+		$data							= $Model->getCustomScore($uid);
+		// 获取进行中的订单
+		// $count							= $Orders->query()->where([['custom_uid','=',$uid],['status','=',1]])->count();
+		// 获取待入账积分
+		// $data['wait_score']				= ((int) $count) * ((int) config('give_orders_score',0));
+		// 返回数据
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+	/**
+	 * 获取交易记录		/api/custom_score/get_record
+	 * 
+	 * */
+	public function get_record(Record $Record){
+		// 接口验签
+        // $this->verify_sign();
+		// 验证登录
+        $uid                    	= $this->checkLogin();
+		// 接收参数
+		$limit						= request('limit',10);
+		// 查询条件
+		$map						= [['custom_uid','=',$uid],['status','=',1]];
+		// 查询数据
+		$Paginator					= $Record->query()->where($map)->orderByDesc('id')->paginate($limit,['id','buy_type','pay_type','score','description','pay_time']);
+		// 重置数据
+		$list						= [];
+		// 获取数据
+		$list['total']				= $Paginator->total();
+		$list['current_page']		= $Paginator->currentPage();
+		$list['per_page']			= $Paginator->perPage();
+		$list['last_page']			= $Paginator->lastPage();
+		$list['data']				= $Paginator->items();
+		// 循环数据
+		foreach ($list['data'] as $key => $value) {
+			// 处理时间
+			$value['pay_time']		= date('Y-m-d H:i:s',$value['pay_time']);
+			// 重组
+			$list['data'][$key] 	= $value;
+		}
+		// 返回数据
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+
+
+}

+ 282 - 0
app/Http/Controllers/Api/Orders.php

@@ -0,0 +1,282 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Orders as Model;
+use App\Models\Product;
+use App\Models\Product\Skus as ProductSkus;
+use App\Http\Requests\Api\Orders as Request;
+use App\Models\Business;
+use App\Models\CustomAddr;
+use App\Models\CustomCoupon;
+use App\Models\OrdersAddr;
+use App\Models\OrdersProduct;
+use App\Models\ShopCart;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 订单接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Orders extends Api{
+
+	/**
+	 * 创建订单						 	/api/orders/create
+	 * 
+	 * @param	string	$car_info		需要下单的产品ID
+	 * @param	string	$buyer_number	需要下单的数量
+	 * 
+	 * */
+	public function create(Request $request,Model $Model,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct,Product $Product,ProductSkus $ProductSkus,CustomCoupon $CustomCoupon,ShopCart $ShopCart,CustomAddr $CustomAddr){
+		// 接口验签
+		// $this->verify_sign();
+		// 验证参数
+		$request->scene('create')->validate();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 接收参数
+		$isCart							= request('is_cart',0);
+		$productList					= request('product_list','[]');
+		$customCouponId					= request('custom_coupon_id',1);
+		$addr							= $CustomAddr->getOne(request('addr_id',0));
+		// 如果不存在数据
+		if( !$addr )					return json_send(['code'=>'error','msg'=>'地址有误,请核对','data'=>['error'=>'没有找到对应的地址']]);
+		// 重组数据
+		$addr							= ['contact_name'=>$addr['contact_name'],'contact_phone'=>$addr['contact_phone'],'contact_province'=>$addr['contact_province'],'contact_city'=>$addr['contact_city'],'contact_area'=>$addr['contact_area'],'contact_addr'=>$addr['contact_addr']];
+		// 解码购买信息
+		$buyList						= json_decode($productList,true);
+		// 如果不存在数据
+		if( empty($buyList) )			return json_send(['code'=>'error','msg'=>'没有需下单的产品','data'=>['error'=>'产品列表为空']]);
+		// 查询产品信息
+		$productList					= $Product->getListByIds(array_column($buyList,'product_id'));
+		$skusList						= $ProductSkus->getListByIds(array_column($buyList,'product_skuid'));
+		// 产品以商业公司分组,方便写入订单
+		$orderProduct					= [];
+		// 产品价格同级,用于优惠券计算
+		$productPrice					= [];
+		// 循环处理购买信息
+		foreach ($buyList as $buyInfo) 	{
+			// 如果产品不存在
+			if( empty($productList[$buyInfo['product_id']]) )	return json_send(['code'=>'error','msg'=>'产品不存在或已下架','data'=>['error'=>'产品不存在或已下架=>'.$buyInfo['product_id']]]);
+			// 获取产信息
+			$productInfo 				= $productList[$buyInfo['product_id']];
+			// 如果存在SKU
+			if( $buyInfo['product_skuid'] ) {
+				// 判断SKU信息存不存在
+				if( empty($skusList[$buyInfo['product_skuid']]) ) return json_send(['code'=>'error','msg'=>'该产品规格不存在或已下架','data'=>['error'=>'SKU不存在或已下架=>'.$buyInfo['product_skuid']]]);
+				// 如果SKU存在,合并产品信息
+				$productInfo			= array_merge($productInfo,$skusList[$buyInfo['product_skuid']]);
+				// 扣除库存
+				$skusList[$buyInfo['product_skuid']]['stock'] = $skusList[$buyInfo['product_skuid']]['stock'] - $buyInfo['buy_num'];
+			}
+			// 判断库存
+			if( $productInfo['stock'] < $buyInfo['buy_num'] )  return json_send(['code'=>'error','msg'=>'产品库存不足','data'=>['error'=>'产品库存不足=>'.$buyInfo['product_id']]]);
+			// 扣除库存
+			$productList[$buyInfo['product_id']]['stock']	= $productList[$buyInfo['product_id']]['stock'] - $buyInfo['buy_num'];
+			// 计算价值
+			$priceTotal					= $buyInfo['buy_num'] * $productInfo['price'];
+			// 购买信息
+			$buyInfo					= ['is_rebate'=>0,'custom_uid'=>$uid,'business_id'=>$productInfo['business_id'],'product_id'=>$buyInfo['product_id'],'buy_num'=>$buyInfo['buy_num'],'price_total'=>$priceTotal,'pay_total'=>$priceTotal,'coupon_total'=>0,'product_name'=>$productInfo['product_name'],'sku_attr_names'=>$productInfo['sku_attr_names'],'product_thumb'=>$productInfo['product_thumb']];
+			// 获取信息
+			if( !isset($orderProduct[$buyInfo['business_id']]) )		$orderProduct[$buyInfo['business_id']] = ['business_id'=>$buyInfo['business_id'],'custom_uid'=>$buyInfo['custom_uid'],'price_total'=>0,'pay_total'=>0,'coupon_total'=>0,'product_list'=>[]];
+			// 订单产品
+			$orderProduct[$buyInfo['business_id']]['price_total']		+= $buyInfo['price_total'];
+			$orderProduct[$buyInfo['business_id']]['pay_total']			+= $buyInfo['price_total'];
+			$orderProduct[$buyInfo['business_id']]['product_list'][]	= $buyInfo;
+			// 商品优惠信息不存在,创建
+			if( !isset($productPrice[$buyInfo['product_id']]) )			$productPrice[$buyInfo['product_id']] = ['price_total'=>0,'rebate_price'=>0];
+			// 计算总价
+			$productPrice[$buyInfo['product_id']]['price_total']		= $productPrice[$buyInfo['product_id']]['price_total'] + $priceTotal;
+		}
+		// 优惠券数据
+		$couponRebate					= $CustomCoupon->getRebatePrice($customCouponId,$uid,$productPrice);
+		// 判断是否使用了优惠券
+		$usedCoupon						= $couponRebate['is_used'];
+		// 获取优惠券扣减金额
+		$productPrice					= $couponRebate['product_price'];
+		// 获取优惠券赠品信息
+		$rebateProduct					= $couponRebate['rebate_product'];
+		// 库存处理
+		foreach ($productList as $key => $value) {
+			$productList[$key]			= ['id'=>$value['id'],'stock'=>$value['stock']];
+		}
+		foreach ($skusList as $key => $value) {
+			$skusList[$key]				= ['id'=>$value['sku_id'],'stock'=>$value['stock']];
+		}
+		// 组合订单数据
+		foreach ($orderProduct as $key => $order) {
+			// 判断哪一家的赠品
+			if( isset($rebateProduct[$order['business_id']]) ){
+				// 循环赠品
+				foreach ( $rebateProduct[$order['business_id']] as $value) {
+					// 没有对应的产品
+					if( !isset($productList[$value['product_id']]) )  $productList[$value['product_id']] = ['id'=>$value['id'],'stock'=>$value['stock']];
+					// 判断库存,如果库存不足,只赠送最后的库存
+					if( $productList[$value['product_id']]['stock'] <= $value['buy_num'] )  $value['buy_num'] = $productList[$value['product_id']]['stock'];
+					// 库存扣减
+					$productList[$value['product_id']]['stock'] = $productList[$value['product_id']]['stock'] - $value['buy_num'];
+					// 追加到订单表
+					$order['product_list'][] = ['is_rebate'=>1,'custom_uid'=>$uid,'business_id'=>$value['business_id'],'product_id'=>$value['product_id'],'buy_num'=>$value['buy_num'],'price_total'=>$value['price_total'],'pay_total'=>$value['pay_total'],'coupon_total'=>$value['coupon_total'],'product_name'=>$value['product_name'],'sku_attr_names'=>$value['sku_attr_names'],'product_thumb'=>$value['product_thumb']];
+				}
+			}
+			// 计算总价格
+			foreach ($order['product_list'] as $k=>$product) {
+				// 商品不存在,不进行扣减
+				if( empty($productPrice[$product['product_id']]['rebate_price']) ) {
+					// 重组
+					$order['product_list'][$k] = $product;
+					continue;
+				}
+				// 总优惠增加
+				$order['coupon_total']	 = $order['coupon_total']  + $productPrice[$product['product_id']]['rebate_price'];
+				// 当前商品的优惠折扣计算
+				$product['coupon_total'] = number_format( $productPrice[$product['product_id']]['rebate_price'] * ($product['price_total'] / $productPrice[$product['product_id']]['price_total']) , 2 , '.' ,'');
+				// 成交小计
+				$product['pay_total']	 = $product['pay_total'] -  $product['coupon_total'];
+				// 重组
+				$order['product_list'][$k] = $product;
+			}
+			// 成交总价
+			$order['pay_total']			= $order['pay_total'] -  $order['coupon_total'];
+			// 成交总价
+			$order['custom_uid']		= $uid;
+			// 重组
+			$orderProduct[$key]			= $order;
+		}
+		// 组合数据,写入订单表,子表
+		DB::beginTransaction();
+		// 写入数据
+		try {
+			// 当前时间
+			$time 						= time();
+			// 更新库存
+			$Product->updateBatch(array_values($productList));
+			// 更新库存
+			$ProductSkus->updateBatch(array_values($skusList));
+			// 循环订单数据
+			foreach ($orderProduct as $order) {
+				// 先获取产品列表,并去除key
+				$productList			= array_values($order['product_list']);
+				// 删除非必要数据
+				unset($order['product_list']);
+				// 创建总订单
+				$orderId				= $Model->add($order);
+				// 如果订单写入失败	
+				if( !$orderId )			{
+					// 回退数据
+					DB::rollBack();
+					// 错误提示
+					return 				json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'订单创建失败']]);
+				}
+				// 创建子订单
+				foreach ($productList as $key=>$value) {
+					// 增加订单ID
+					$value['order_id']	= $orderId;
+					// 增加订单ID
+					$value['insert_time']= $time;
+					$value['update_time']= $time;
+					// 结果
+					$productList[$key]	= $value;
+				}
+				// 写入子表
+				$result					= $OrdersProduct->query()->insert($productList);
+				// 如果扣减失败
+				if( !$result )												{
+					// 回退数据
+					DB::rollBack();
+					// 提示信息
+					return				json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'子订单创建失败']]);
+				}
+				// 写入订单地址表
+				$addr['order_id']		= $orderId;
+				// 写入订单地址表
+				$result 				= $OrdersAddr->add($addr);
+				// 地址写入失败
+				if( !$result )			{
+					// 回退数据
+					DB::rollBack();
+					// 提示信息
+					return				json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'地址写入失败']]);
+				}
+				// 如果使用了优惠券
+				if( $usedCoupon )		$CustomCoupon->edit($usedCoupon,['status'=>1,'order_id'=>$orderId]);
+				// 购物车
+				if( $isCart )			$ShopCart->query()->where([['custom_uid','=',$uid]])->whereIn('skuid',array_column($buyList,'product_skuid'))->delete();
+			}
+			// 提交数据
+			DB::commit();
+			// 返回结果
+			return						json_send(['code'=>'success','msg'=>'下单成功','data'=>['id'=>null]]);
+			// 返回结果
+		} catch (\Throwable $th) {
+			// 回退数据
+			DB::rollBack();
+			// 判断结果,如果库存扣减失败的话
+			if( stripos($th->getMessage(),'UNSIGNED') )  return json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'产品库存扣减失败']]);
+			// 下单失败提示
+			return						json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>$th->getMessage().$th->getLine()]]);
+		}
+	}
+
+
+	/**
+	 * 获取产品列表		 /api/orders/get_list
+	 * 
+	 * @param	string	$name		    产品名称
+	 * @param	int		$page			页码,默认1
+	 * @param	int		$limit			每页条数,默认10条
+	 * 
+	 * */
+	public function get_list(Request $request,Model $Model,OrdersProduct $OrdersProduct,Business $Business){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_list')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$status						= request('status',0);
+		$limit						= request('limit',10);
+		// 显示
+		$map						= [['custom_uid','=',$uid]];
+		// 查询状态
+		if( $status )				$map[] = ['status','=',$status];
+		// 查询
+		$Paginator					= $Model->query()->where($map)->orderByDesc('id')->paginate($limit,['id','pay_total','status','price_total','coupon_total','business_id','pay_total','insert_time']);
+		// 订单产品
+		$productList 				= $OrdersProduct->query()->whereIn('order_id', array_column($Paginator->items(),'id'))->select(['id as item_id','order_id','product_id','buy_num','is_rebate','sku_attr_names as product_spec','product_name','product_thumb',])->get()->toArray();
+		// 循环处理
+		foreach ($Paginator as $key => $order) {
+			// 商品列表
+			$itemList				= [];
+			// 返回结果
+			foreach ($productList as $item) {
+				// 产品图路径
+				$item['product_thumb']	= path_compat($item['product_thumb']);
+				// 如果是订单的
+				if( $item['order_id'] == $order['id'] ) $itemList[]	= $item;
+			}
+			// 获取子列表
+			$order['state']			= (string) $Model->getState($order['status'],'state');
+			// 获取子列表
+			$order['business_name']	= (string) $Business->getOne($order['business_id'],'name');
+			// 获取子列表
+			$order['contents_class']= 0;
+			// 获取子列表
+			$order['product_list']	= $itemList;
+			// 重组
+			$Paginator[$key]		= $order;
+		}
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+}

+ 34 - 0
app/Http/Controllers/Api/Orders/Banner.php

@@ -0,0 +1,34 @@
+<?php namespace App\Http\Controllers\Api\Orders;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Orders\Banner as Model;
+
+/**
+ * 订单落地页Banner
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Banner extends Api{
+	
+	
+	/**
+	 * 获取客户信息			/api/orders_banner/get_list
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function get_list(Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+		// 检查登录
+		$uid							= $this->getUid();
+		// 查新客户类型
+		$list			                = $Model->getList();
+		// 
+        $list                           = array_values($list);
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+	
+}

+ 161 - 0
app/Http/Controllers/Api/Product.php

@@ -0,0 +1,161 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Http\Requests\Api\Product as Request;
+use App\Models\Business;
+use App\Models\Custom;
+use App\Models\Product as Model;
+use App\Models\Product\Attr as ProductAttr;
+use App\Models\Product\City as ProductCity;
+use App\Models\Product\Spec as ProductSpec;
+use App\Models\Product\Skus as ProductSkus;
+
+/**
+ * 产品接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Product extends Api{
+
+	/**
+	 * 获取产品列表		 /api/product/get_list
+	 * 
+	 * @param	string	$name		    产品名称
+	 * @param	int		$page			页码,默认1
+	 * @param	int		$limit			每页条数,默认10条
+	 * 
+	 * */
+	public function get_list(Request $request,Model $Model,Custom $Custom){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_list')->validate();
+		// 检查登录
+		$uid						= $this->getUid();
+		// 获取客户信息
+		$custom						= $uid ? $Custom->getOne($uid) : [];
+		// 接收参数
+		$name					    = request('name','');
+		$limit						= request('limit',10);
+		// 显示
+		$map						= [['status','=','0'],['stock','>',0]];
+		// 分类ID
+		if( $name )					$map[] = ['name','like','%'.$name.'%'];
+		// 是否有城市
+		$wherIn						= empty($custom['city_id']) ? [1] : [1,$custom['city_id']];
+		// 获取分页信息
+		$Paginator					= $Model->query()
+										->join('product_city','product_city.product_id','=','product.id')
+										->where($map)
+										->whereIn('product_city.city_id',$wherIn)
+										->groupBy('product_id')
+										->paginate($limit,['product.id','product.name','product.thumb','product.spec','product.price','product.market_price','product.stock']);
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 处理请求
+		foreach ( $data['data'] as $key => $value ) {
+			// 处理数据
+			$value['thumb'] 		= path_compat($value['thumb']);
+			$value['poster'] 		= path_compat($value['poster']);
+			// 重组数据
+			$data['data'][$key]		= $value;
+		}
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+    /**
+	 * 获取产品列表		 /api/product/get_detail
+	 * 
+	 * @param	int     $id		        产品id
+	 * 
+	 * */
+	public function get_detail(Request $request,Model $Model,Business $Business,ProductAttr $ProductAttr,ProductSpec $ProductSpec,ProductSkus $ProductSkus ){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_detail')->validate();
+		// 检查登录
+		// $uid						= $this->checkLogin();
+		// 接收参数
+		$id						    = request('id',0);
+		// 显示
+		$map[]						= ['status','=','0'];
+		// 查询
+		$data   					= $Model->query()->where($map)->find($id,['id','name','thumb','stock','spec','poster','price','business_id','market_price']);
+		// 如果没有数据
+        if( !$data )                return json_send(['code'=>'error','msg'=>'产品已下架','data'=>['error'=>'产品已下架或不存在']]);
+		// 转数组
+		$data						= $data->toArray();
+		// 处理数据
+		$data['thumb'] 				= path_compat($data['thumb']);
+		$data['poster'] 			= path_compat($data['poster']);
+		$data['description'] 		= $Model->getDesc($id);
+		$data['business_info'] 		= $Business->getOne($data['business_id']);
+		// 获取产品属性
+		$attr						= $ProductAttr->getListByProductId($id);
+		// 规格属性
+		$specAttr					= [];
+		// 获取数据
+		foreach ($attr as $value) {
+			// 默认未选中
+			$value['active']		= 0;
+			$specAttr[$value['spec_id']]['spec_id']		= $value['spec_id'];
+			$specAttr[$value['spec_id']]['spec_name'] 	= $ProductSpec->getOne($value['spec_id'],'name');
+			$specAttr[$value['spec_id']]['attr_list'][]	= $value;
+		}
+		// 获取规格详情数据
+		$data['product_attr']		= array_values($specAttr);
+		// 获取SKU数据
+		$data['product_sku']		= $ProductSkus->getListByProductId($id);
+		// 手机号
+		if( isset($data['business_info']['phone']) ) unset($data['business_info']['phone']);
+		if( isset($data['business_info']['logopic']) ) $data['business_info']['logopic'] = path_compat($data['business_info']['logopic']);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+	/**
+	 * 获取产品列表		 /api/product/get_sku
+	 * 
+	 * @param	int     $id		        产品id
+	 * 
+	 * */
+	public function get_sku(Request $request,ProductAttr $ProductAttr,ProductSpec $ProductSpec,ProductSkus $ProductSkus ){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_sku')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$id						    = request('id',0);
+		// 获取产品属性
+		$attr						= $ProductAttr->getListByProductId($id);
+		// 规格属性
+		$specAttr					= [];
+		// 获取数据
+		foreach ($attr as $value) {
+			// 默认未选中
+			$value['active']		= 0;
+			$specAttr[$value['spec_id']]['spec_id']		= $value['spec_id'];
+			$specAttr[$value['spec_id']]['spec_name'] 	= $ProductSpec->getOne($value['spec_id'],'name');
+			$specAttr[$value['spec_id']]['attr_list'][]	= $value;
+		}
+		// 获取规格详情数据
+		$data['product_attr']		= $specAttr;
+		// 获取SKU数据
+		$data['product_sku']		= $ProductSkus->getListByProductId($id);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+}

+ 60 - 0
app/Http/Controllers/Api/Score/Clockin.php

@@ -0,0 +1,60 @@
+<?php namespace App\Http\Controllers\Api\Score;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Score\Clockin as Model;
+
+/**
+ * 任务-打卡
+ * 
+ * @author	刘相欣
+ * 
+ * */
+class Clockin extends Api
+{
+    /**
+     * 列表                     /api/score_clockin/get_list
+     * 
+     */
+    public function get_list(Model $Model)
+    {
+        // 接口验签
+		// $this->verify_sign();
+		// 验证登录
+		$uid						= $this->getUid();
+        // 获取列表
+        $list                       = $Model->getList();
+        $isMark                     = $Model->isMarkClock($uid);
+        $isMark['finish_day']       = empty($isMark['finish_day'])?0:$isMark['finish_day'];
+        // 循环处理
+        foreach ( $list as $key => $value ) {
+            // 是否已打卡,打卡天数内(含)为已打卡
+            $value['is_finish']     = $isMark['finish_day'] >= $value['what_day'] ? 1 : 0;
+            // 重新赋值
+            $list[$key]             = $value;
+        }
+        // 去除主键
+        $list                       = array_values($list);
+        // 返回结果
+        return                      json_send(['code'=>'success','msg'=>'获取成功','data'=>['list'=>$list,'is_mark'=>$isMark]]);
+    }
+
+    /**
+     * 打卡                         /api/score_clockin/finish
+     * 
+     */
+    public function finish(Model $Model)
+    {
+        // 接口验签
+		// $this->verify_sign();
+		// 验证登录
+		$uid						    = $this->checkLogin();
+        // 获取打卡次数
+        $result                         = $Model->finish($uid);
+        // 失败结束
+        if( isset($result['error']) )   return json_send(['code'=>'error','msg'=>$result['error'],'data'=>'']);
+        // 返回结果
+        return                          json_send(['code'=>'success','msg'=>'打卡成功','data'=>$result]);
+    }
+
+
+}

+ 166 - 0
app/Http/Controllers/Api/Score/Orders.php

@@ -0,0 +1,166 @@
+<?php namespace App\Http\Controllers\Api\Score;
+
+use App\Models\CustomAddr;
+use App\Models\Score\Product;
+use App\Http\Controllers\Api\Api;
+use App\Models\Score\Orders as Model;
+use App\Models\Score\OrdersAddr as OrdersAddr;
+use App\Http\Requests\Api\Score\Orders as Request;
+use Illuminate\Support\Facades\DB;
+use App\Models\CustomScore;
+/**
+ * 订单接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Orders extends Api{
+	
+	
+	/**
+	 * 创建订单						 	/api/score_order/create
+	 * 
+	 * @param	string	$car_info		需要下单的产品ID
+	 * @param	string	$buyer_number	需要下单的数量
+	 * 
+	 * */
+	public function create(Request $request,Model $Model,CustomAddr $CustomAddr,Product $Product,OrdersAddr $OrdersAddr,CustomScore $CustomScore){
+		// 接口验签
+		// $this->verify_sign();
+		// 验证参数
+		$request->scene('create')->validate();
+		// 检查登录
+		$uid							= $this->checkLogin();
+		// 接收参数
+		$productId						= request('product_id',0);
+		$buyNum							= request('buy_num',0);
+		$addrId							= request('addr_id',0);
+		$buyType						= 3;
+		$payType						= 1;
+		// 获取地址
+		$addr							= $CustomAddr->getOne($addrId);
+		// 如果不存在数据
+		if( !$addr )					return json_send(['code'=>'error','msg'=>'地址有误,请核对','data'=>['error'=>'没有找到对应的地址']]);
+		// 重组数据
+		$addr							= ['contact_name'=>$addr['contact_name'],'contact_phone'=>$addr['contact_phone'],'contact_province'=>$addr['contact_province'],'contact_city'=>$addr['contact_city'],'contact_area'=>$addr['contact_area'],'contact_addr'=>$addr['contact_addr']];
+		// 解码
+		$productList					= $Product->getOne($productId);
+		// 如果产品不存在
+		if( !$productList )				return json_send(['code'=>'error','msg'=>'产品不存在或已下架','data'=>['error'=>'产品ID不存在'.$productId]]);
+		// 如果产品库存不足主产品
+		if( $productList['stock'] < $buyNum )	return json_send(['code'=>'error','msg'=>'产品库存不足','data'=>['error'=>'产品库存不足']]);
+		// 获取积分信息
+		$balance						= $CustomScore->getBalanceByUid($uid);
+		// 如果剩余积分不足
+		if( $balance < $buyNum * $productList['score'] ) return json_send(['code'=>'error','msg'=>'积分不足','data'=>['error'=>'积分不足']]);
+		// 总共积分
+		$order['score_total']			= $buyNum * $productList['score'];
+		$order['product_id']			= $productId;
+		$order['buy_num']				= $buyNum;
+		$order['custom_uid']			= $uid;
+		$order['status']				= 1;
+		// 组合数据,写入订单表,子表
+		DB::beginTransaction();
+		// 写入数据
+		try {
+			// 扣减库存
+			$result 					= $Product->edit($productId,['stock'=>DB::raw('stock+'.$buyNum)]);
+			// 如果扣减失败
+			if( !$result )				{
+				// 回退数据
+				DB::rollBack();
+				// 提示信息
+				return					json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>'产品库存扣减失败']]);
+			}
+			// 创建总订单
+			$orderId					= $Model->add($order);
+			// 如果扣减失败
+			if( !$orderId )				{
+				// 回退数据
+				DB::rollBack();
+				// 提示信息
+				return					json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>'订单创建失败']]);
+			}
+			// 积分扣减
+			$result 					= $CustomScore->trade($uid,$orderId,($order['score_total']*-1),$buyType,$payType);
+			// 地址写入失败
+			if( isset($result['error']) ) {
+				// 回退数据
+				DB::rollBack();
+				// 提示信息
+				return					json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>result['error']]]);
+			}
+			// 订单ID
+			$addr['order_id']			= $orderId;
+			// 写入订单地址表
+			$result 					= $OrdersAddr->add($addr);
+			// 地址写入失败
+			if( !$result )				{
+				// 回退数据
+				DB::rollBack();
+				// 提示信息
+				return					json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>'地址写入失败']]);
+			}
+			// 提交数据
+			DB::commit();
+			// 返回结果
+			return						json_send(['code'=>'success','msg'=>'兑换成功','data'=>['id'=>$orderId]]);
+			
+		} catch (\Throwable $th) {
+			// 回退数据
+			DB::rollBack();
+			// 判断结果,如果库存扣减失败的话
+			if( stripos($th->getMessage(),'UNSIGNED') )  				return json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>'产品库存扣减失败']]);
+			// 下单失败提示
+			return						json_send(['code'=>'error','msg'=>'兑换失败','data'=>['error'=>$th->getMessage()]]);
+		}
+	}
+
+
+
+
+
+	/**
+	 * 获取列表		 /api/score_order/get_list
+	 * 
+	 * @param	string	$name		    产品名称
+	 * @param	int		$page			页码,默认1
+	 * @param	int		$limit			每页条数,默认10条
+	 * 
+	 * */
+	public function get_list(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_list')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$status						= request('status',0);
+		$limit						= request('limit',10);
+		// 显示
+		$map						= [['score_orders.custom_uid','=',$uid]];
+		// 查询状态
+		if( $status )				$map[] = ['score_orders.status','=',$status];
+		// 查询
+		$Paginator					= $Model->query()->join('score_product','score_orders.product_id','=','score_product.id')->where($map)->orderByDesc('score_orders.id')->paginate($limit,['score_orders.id','score_orders.product_id','score_orders.score_total','score_orders.buy_num','score_orders.status','score_orders.insert_time','score_product.name as product_name','score_product.thumb as product_thumb','score_product.spec as product_spec']);
+		// 循环处理数据
+		foreach ($Paginator as $key => $value) {
+			// 产品图路径
+			$value['state']			= $Model->getState($value['status'],'state');
+			// 产品图路径
+			$value['product_thumb']	= path_compat($value['product_thumb']);
+			// 重组
+			$Paginator[$key]		= $value;
+		}
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+}

+ 87 - 0
app/Http/Controllers/Api/Score/Product.php

@@ -0,0 +1,87 @@
+<?php namespace App\Http\Controllers\Api\Score;
+
+use App\Http\Controllers\Api\Api;
+use App\Http\Requests\Api\Score\Product as Request;
+use App\Models\Score\Product as Model;
+
+/**
+ * 产品接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Product extends Api{
+
+	/**
+	 * 获取产品列表		 /api/score_product/get_list
+	 * 
+	 * @param	string	$name		    产品名称
+	 * @param	int		$page			页码,默认1
+	 * @param	int		$limit			每页条数,默认10条
+	 * 
+	 * */
+	public function get_list(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_list')->validate();
+		// 检查登录
+		$uid						= $this->getUid();
+		// 接收参数
+		$name					    = request('name','');
+		$limit						= request('limit',10);
+		// 显示
+		$map						= [['status','=','0']];
+		// 分类ID
+		if( $name )					$map[] = ['name','like','%'.$name.'%'];
+		// 查询
+		$Paginator					= $Model->query()->where($map)->paginate($limit,['id','name','thumb','spec','score']);
+		// 获取数据
+		$data['total']				= $Paginator->total();
+		$data['current_page']		= $Paginator->currentPage();
+		$data['per_page']			= $Paginator->perPage();
+		$data['last_page']			= $Paginator->lastPage();
+		$data['data']				= $Paginator->items();
+		// 处理请求
+		foreach ( $data['data'] as $key => $value ) {
+			// 处理数据
+			$value['thumb'] 		= path_compat($value['thumb']);
+			// 重组数据
+			$data['data'][$key]		= $value;
+		}
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+
+    /**
+	 * 获取产品列表		 /api/score_product/get_detail
+	 * 
+	 * @param	int     $id		        产品id
+	 * 
+	 * */
+	public function get_detail(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_detail')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$id						    = request('id',0);
+		// 显示
+		$map[]						= ['status','=','0'];
+		// 查询
+		$data   					= $Model->query()->where($map)->find($id,['id','name','thumb','stock','spec','score']);
+		// 如果没有数据
+        if( !$data )                return json_send(['code'=>'error','msg'=>'产品已下架','data'=>['error'=>'产品已下架或不存在']]);
+		// 转数组
+		$data						= $data->toArray();
+		// 处理数据
+		$data['thumb'] 				= path_compat($data['thumb']);
+		$data['description'] 		= $Model->getDesc($id);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
+	}
+
+}

+ 215 - 0
app/Http/Controllers/Api/ShopCart.php

@@ -0,0 +1,215 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Http\Requests\Api\ShopCart as Request;
+use App\Models\Product\Skus as ProductSkus;
+use App\Models\ShopCart as Model;
+
+/**
+ * 购物车接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class ShopCart extends Api{
+
+	/**
+	 * 添加	 /api/shop_cart/add
+	 * 
+	 * @param	int		$product_id		产品ID
+	 * @param	int		$buy_num		添加数量
+	 * 
+	 * */
+	public function add(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('add')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$data['product_id']			= request('product_id',0);
+		$data['skuid']				= request('skuid',0);
+		$data['buy_num']			= request('buy_num',1);
+		$data['custom_uid']			= $uid;
+		// 查询
+		$id							= $Model->query()->where([['custom_uid','=',$uid],['product_id','=',$data['product_id']],['skuid','=',$data['skuid']]])->value('id');
+		// 如果存在id,更新数量
+		$result 					= $id ? $Model->incrBuyNum($id,$uid,$data['buy_num']) : $Model->add($data);
+		// 提交结果
+		if( !$result )				return json_send(['code'=>'success','msg'=>'加入购物车失败','data'=>['error'=>'加入购物车失败']]);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'添加成功','data'=>$data]);
+	}
+
+
+    /**
+	 * 更新		 /api/shop_cart/edit
+	 * 
+	 * @param	int     $id		        购物车id
+	 * 
+	 * */
+	public function edit(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('edit')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$id							= request('id',0);
+		$data['buy_num']			= request('buy_num',1);
+		// 如果存在id,更新数量
+		$result 					= $Model->edit($id,$uid,$data);
+		// 提交结果
+		if( !$result )				return json_send(['code'=>'success','msg'=>'更新失败','data'=>['error'=>'更新购物车失败']]);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'更新成功','data'=>$data]);
+	}
+
+	/**
+	 * 更新		 /api/shop_cart/del
+	 * 
+	 * @param	int     $id		        购物车id
+	 * 
+	 * */
+	public function del(Request $request,Model $Model){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('del')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$id							= request('id',0);
+		// 如果存在id,更新数量
+		$result 					= $Model->del($id,$uid);
+		// 提交结果
+		if( !$result )				return json_send(['code'=>'success','msg'=>'删除失败','data'=>['error'=>'删除购物车失败']]);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'删除成功','data'=>['id'=>$id]]);
+	}
+
+
+	/**
+	 * 获取列表		 /api/shop_cart/get_list
+	 * 
+	 * @param	int     $id		        购物车id
+	 * 
+	 * */
+	public function get_list(Request $request,Model $Model,ProductSkus $ProductSkus){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('get_list')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 显示
+		$map						= [['shop_cart.custom_uid','=',$uid]];
+		// 查询
+		$list						= $Model->query()->join('product','shop_cart.product_id','=','product.id')->where($map)->get(['shop_cart.id','shop_cart.checked','shop_cart.product_id','shop_cart.skuid','shop_cart.buy_num','product.stock','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status'])->toArray();
+		// 判断结果
+		$skusList					= $ProductSkus->getListByIds(array_column($list,'skuid'));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 如果有sku
+			if( $value['skuid'] )	{
+				// 是否存在
+				$isExist			= false;
+				// 循环SKU
+				foreach ($skusList as $sku) {
+					// 如果SKU存在的话
+					if( $sku['sku_id'] == $value['skuid'] ) {
+						$value['price']	= $sku['price'];
+						$value['spec']	= $sku['sku_attr_names'];
+						$value['stock']	= $sku['stock'];
+						$isExist		= true;
+					}
+				}
+				// 如果不存在,状态变动
+				if( !$isExist )		$value['product_status'] = 4;
+			}
+			// 产品图路径
+			$value['thumb']			= path_compat($value['thumb']);
+			// 库存超出的时候
+			if($value['buy_num'] > $value['stock'] ) $value['buy_num'] = $value['stock'];
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+
+
+
+	/**
+	 * 结算列表		 	 /api/shop_cart/check_list
+	 * 
+	 * @param	int     $id		        购物车id
+	 * 
+	 * */
+	public function check_list(Request $request,Model $Model,ProductSkus $ProductSkus){
+		// 接口验签
+		// $this->verify_sign();
+        // 验证参数
+		$request->scene('check_list')->validate();
+		// 检查登录
+		$uid						= $this->checkLogin();
+		// 接收参数
+		$cartIds					= request('cart_ids','');
+		// 转成数组
+		$cartIds					= explode(',',$cartIds);
+		// 循环处理
+		foreach ($cartIds as $key => $value) {
+			// 如果不是数值
+			if( $value < 1 )		unset($cartIds[$key]);
+		}
+		// 如果不存在的话
+		if( !$cartIds )				return json_send(['code'=>'error','msg'=>'请选择可用产品','data'=>['error'=>request('cart_ids','')]]);
+		// 显示
+		$map						= [['shop_cart.custom_uid','=',$uid],['product.status','=',0]];
+		// 查询
+		$list						= $Model->query()->join('product','shop_cart.product_id','=','product.id')->whereIn('shop_cart.id',$cartIds)->where($map)->get(['shop_cart.id','shop_cart.checked','shop_cart.product_id','shop_cart.skuid','shop_cart.buy_num','product.stock','product.spec','product.thumb','product.name','product.price','product.market_price','product.status as product_status'])->toArray();
+		// 判断结果
+		$skusList					= $ProductSkus->getListByIds(array_column($list,'skuid'));
+		// 循环处理数据
+		foreach ($list as $key => $value) {
+			// 如果有sku
+			if( $value['skuid'] )	{
+				// 是否存在
+				$isExist			= false;
+				// 循环SKU
+				foreach ($skusList as $sku) {
+					// 如果SKU存在的话
+					if( $sku['sku_id'] == $value['skuid'] ) {
+						$value['price']	= $sku['price'];
+						$value['spec']	= $sku['sku_attr_names'];
+						$value['stock']	= $sku['stock'];
+						$isExist		= true;
+					}
+				}
+				// 如果不存在,状态变动
+				if( !$isExist )		{
+					unset($list[$key]);
+					continue;
+				}
+			}
+			// 如果不存在,状态变动
+			if( $value['stock'] <= 0 )		{
+				unset($list[$key]);
+				continue;
+			}
+			// 产品图路径
+			$value['thumb']			= path_compat($value['thumb']);
+			// 库存超出的时候
+			if($value['buy_num'] > $value['stock'] ) $value['buy_num'] = $value['stock'];
+			// 重组
+			$list[$key]				= $value;
+		}
+		// 重组数组
+		$list						= array_values($list);
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'获取成功','data'=>$list]);
+	}
+
+}

+ 22 - 0
app/Http/Controllers/Api/Test.php

@@ -0,0 +1,22 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+
+/**
+ * 测试接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Test extends Api{
+	
+	
+	/**
+	 * 同步			/api/test/sync_user
+	 * 
+	 * */
+	public function sync_user(){
+        
+    }
+
+}

+ 53 - 0
app/Http/Controllers/Api/Wechat.php

@@ -0,0 +1,53 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Api\Api;
+use App\Models\Custom;
+use App\Facades\Servers\WechatMini\Mini;
+
+/**
+ * 微信接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Wechat extends Api{
+	
+	
+	/**
+	 * 小程序手机号授权				/api/wechat/phone_number
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function phone_number(Custom $Custom){
+		// 接口验签
+		// $this->verify_sign();
+		// 接收参数
+		$code									= request('code','');
+		// 授权结果
+		$result									= Mini::getUserPhone($code);
+		// 如果所需字段不存在
+		if( isset($result['error']) ) 			return json_send(['code'=>'error','msg'=>'授权失败','data'=>['error'=>$result['error']]]);
+		// 如果所需字段不存在
+		if( empty($result['purePhoneNumber']) ) return json_send(['code'=>'error','msg'=>'未获取到手机号','data'=>['error'=>'未获取到手机号']]);
+		// 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+		$phone									= $result['purePhoneNumber'];
+		// 查询用户
+		$custom									= $Custom->getOneByPhone($phone);
+		// 如果用户状态被拉黑,不允许登录
+		if( !empty($custom['status']) )			return json_send(['code'=>'error','msg'=>'禁用账号','data'=>['error'=>'禁用账号']]);
+		// 如果没有ID
+		if( empty($custom['uid']) )				{
+			// 注册账号
+			$custom['uid'] 						= $Custom->add(['phone'=>$phone,'username'=>hide_phone($phone)]);
+			// 注册失败
+			if( empty($custom['uid']) )			return json_send(['code'=>'error','msg'=>'注册失败,请重试','data'=>['error'=>'注册失败,请重试']]);
+		}
+		// 进行登录
+		$token									= $Custom->createLoginAuthcode($custom['uid'],time());
+		// 返回结果
+		return									json_send(['code'=>'success','msg'=>'登录成功','data'=>$token]);
+	}
+
+
+}

+ 192 - 0
app/Http/Controllers/Api/WechatWork.php

@@ -0,0 +1,192 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Facades\Servers\WechatMini\Mini;
+use App\Http\Controllers\Api\Api;
+use App\Models\Work\State as WorkState;
+use App\Models\Work\External as WorkExternal;
+use App\Facades\Servers\WechatWork\CorpTag as CorpTag;
+use App\Facades\Servers\WechatWork\ExternalContact as ExternalContact;
+use App\Models\Work\Tag as WorkTag;
+use App\Models\Work\User as WorkUser;
+use EasyWeChat\Factory;
+use Vinkla\Hashids\Facades\Hashids;
+
+/**
+ * 企业微信微信接口
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class WechatWork extends Api{
+	
+	/**
+	 * 消息推送				/api/workwechat/notify
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function notify(){
+		// 获取配置
+		$app				= Factory::work(config('wechat.work'));
+		// 接收消息通知
+		$app->server->push(function($message) {
+			// $message		= json_decode('{"ToUserName":"wwcdbc686326b51a89","FromUserName":"sys","CreateTime":"1727420114","MsgType":"event","Event":"change_external_contact","ChangeType":"add_external_contact","UserID":"LiangYan","ExternalUserID":"wmnltlDwAAcHuNEggrIxLtb-Buzk0KkQ","State":"state_id=9","WelcomeCode":"G2OYXUVxNyu3YOb3-oELMOCX1XSLWoeeGjl_HOw7k1E"}',true);
+			try {
+				// 处理结果
+				$result		= [];
+				// 外部联系人变动
+				if( $message['Event'] == 'change_external_contact' ) {
+					// 添加企业客户事件,// 注册用户
+					if( $message['ChangeType'] == 'add_external_contact' )  $result = $this->addExternal($message);
+					// 编辑企业客户事件
+					if( $message['ChangeType'] == 'edit_external_contact' ) $result	= $this->editExternal($message);
+					// 删除企业客户事件
+					if( $message['ChangeType'] == 'del_external_contact' )	$result	= $this->delExternal($message);
+					// 删除跟进成员事件
+					if( $message['ChangeType'] == 'del_follow_user' 	)	$result	= $this->delFollow($message);
+				}
+				// 错误
+				if( isset($result['error']) )  return json_send(['code'=>'work_notify','msg'=>$result['error'],'data'=>$message]);
+				// 成功
+				return			json_send(['code'=>'success','msg'=>'notify','data'=>$message]);
+			} catch (\Throwable $th) {
+				// 成功
+				return			json_send(['code'=>'error','msg'=>'notify','data'=>['message'=>$message,'msg'=>$th->getMessage()]]);
+			}
+		});
+		$response 			= $app->server->serve();
+		$response->send();
+	}
+
+	/**
+	 * 添加企业客户事件
+	 * 
+	 */
+	public function addExternal($message){
+		// 实例
+		$WorkExternal			= New WorkExternal;
+		$WorkState				= new WorkState;
+		$WorkUser				= New WorkUser;
+		$WorkTag				= New Worktag;
+		// 通过state获取附加参数以判断用户类型
+		parse_str($message['State'],$state);
+		// 获取附加参数
+		$state						= empty($state['state_id']) ? [] : $WorkState->getOne($state['state_id']);
+		// 存在客户标签,给客户增加标签
+		if( !empty($state['tags']) ) CorpTag::markTags($message['UserID'], $message['ExternalUserID'],explode(',',$state['tags']));
+		// 获取客户详情
+		$extUser					= ExternalContact::getOne($message['ExternalUserID']);
+		// 如果没有获取到数据的话
+		if( !$extUser )				return ['error'=>'企微ID不存在'];
+		// 如果存在用户类型,且有外部联系人信息
+		if( !empty($state['user_type']) && !empty($extUser['external_contact']) ) $extUser['external_contact']['user_type'] = $state['user_type'];
+		// 判断企微用户是否存在
+		$external					= $WorkExternal->getOneByExtUserId($message['ExternalUserID']);
+		// 更新或者新增客户
+		$id 						= $external ? $external['id'] : $WorkExternal->workAdd($extUser['external_contact']);
+		// 如果添加失败
+		if( !$id )					return ['error'=>'新用户添加失败'];
+		// 跳转链接
+		$link						= Mini::getUrlLink('pages/bind/user',http_build_query(['kailin_uid'=>Hashids::encodeHex($id),'work_userid'=>$message['UserID']]));
+		// 欢迎语
+		$welcome					= $link ? ['link'=>['title'=>'请点此填写表单','desc'=>'填写表单信息为了给您提供更优服务','url'=>$link]] : ['text'=>['content'=>'请联系您的对接人员为您录入信息']];
+		// 发送欢迎语
+		ExternalContact::sendWelcome($message['WelcomeCode'],$welcome);
+		// 循环跟进人员
+		foreach ($extUser['follow_user'] as $workUser)		{
+			// 如果是当前的跟进人员
+			if( $workUser['userid'] == $message['UserID'] ) {
+				// 处理跟进关系
+				$WorkUser		= $WorkUser->upsertOne($extUser['external_contact'],$workUser);
+				// 处理标签
+				if( $workUser['tags'] )	$WorkTag->upsertTags($message['UserID'],$message['ExternalUserID'],$workUser['tags']);
+			}
+		}
+		// 结果
+		return 						['success'=>'处理完成'];
+	}
+
+	/**
+	 * 编辑企业客户事件
+	 * 
+	 */
+	public function editExternal($message){
+		// 实例
+		$WorkExternal				= New WorkExternal;
+		$WorkUser					= New WorkUser;
+		$WorkTag					= New WorkTag;
+		// 获取客户详情
+		$extUser					= ExternalContact::getOne($message['ExternalUserID']);
+		// 如果没有获取到数据的话
+		if( !$extUser )				return ['error'=>'企微ID不存在'];
+		// 判断用户是否已经存在
+		$external					= $WorkExternal->getOneByExtUserId($message['ExternalUserID']);
+		// 如果更新或者新增客户
+		$id 						= $external ? $external['id'] : $WorkExternal->workAdd($extUser['external_contact']);
+		// 如果添加失败
+		if( !$id )					return ['error'=>'客户信息更新失败'];
+		// 循环跟进人员
+		foreach ($extUser['follow_user'] as $workUser) {
+			// 如果是当前的跟进人员
+			if( $workUser['userid'] == $message['UserID'] ){
+				// 处理跟进关系
+				$WorkUser			= $WorkUser->upsertOne($extUser['external_contact'],$workUser);
+				// 处理标签
+				$WorkTag->upsertTags($message['UserID'],$message['ExternalUserID'],$workUser['tags']);
+			}
+		}
+		// 返回结果
+		return 						['success'=>'处理完成'];
+	}
+
+
+	/**
+	 * 删除企业客户事件
+	 * 
+	 */
+	public function delExternal($message){
+		// 实例
+		$WorkUser					= New WorkUser;
+		$WorkTag					= New WorkTag;
+		// 获取客户详情
+		$extUser					= ExternalContact::getOne($message['ExternalUserID']);
+		// 如果没有获取到数据的话
+		if( !$extUser )				return ['error'=>'企微ID不存在'];
+		// 删除跟进人员信息
+		$WorkUser->delByExtUser($message['ExternalUserID'],$message['UserID']);
+		// 删除跟进人员标签
+		$WorkTag->delByExtUser($message['ExternalUserID'],$message['UserID']);
+		// 返回结果
+		return 						['success'=>'处理完成'];
+	}
+
+	/**
+	 * 客户删除跟进人员事件
+	 * 
+	 */
+	public function delFollow($message){
+		// 实例
+		$WorkExternal				= New WorkExternal;
+		$WorkUser					= New WorkUser;
+		// 获取客户详情
+		$extUser					= ExternalContact::getOne($message['ExternalUserID']);
+		// 如果没有获取到数据的话
+		if( !$extUser )				return ['error'=>'企微ID不存在'];
+		// 判断用户是否已经存在
+		$external					= $WorkExternal->getOneByExtUserId($message['ExternalUserID']);
+		// 如果有用户的话
+		if( !$external )			return ['success'=>'用户不存在无需处理'];
+		// 如果更新或者新增客户
+		$id 						= $external ? $external['id'] : $WorkExternal->workAdd($extUser['external_contact']);
+		// 如果添加失败
+		if( !$id )					return ['error'=>'客户信息更新失败'];
+		// 返回结果
+		$result 					= $WorkUser->updateByExtUser($message['ExternalUserID'],$message['UserID'],['status'=>2]);
+		// 如果添加失败
+		if( !$result )				return ['error'=>'状态变更失败'];
+		// 返回结果
+		return 						['success'=>'处理完成'];
+	}
+
+
+}

+ 37 - 0
app/Http/Controllers/Api/WeiZan/Orders.php

@@ -0,0 +1,37 @@
+<?php namespace App\Http\Controllers\Api\WeiZan;
+
+use App\Http\Controllers\Api\Api;
+use App\Http\Requests\Admin\Orders as Request;
+use App\Models\Custom;
+use App\Models\FilesManager;
+use App\Models\Orders as Model;
+use App\Models\OrdersAddr;
+use App\Models\OrdersProduct;
+
+/**
+ * 微赞订单
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class Orders extends Api{
+	
+	
+	/**
+	 * 订单导入						 	/api/weizan_orders/import
+	 * 
+	 * @param	string	$car_info		需要下单的产品ID
+	 * @param	string	$buyer_number	需要下单的数量
+	 * 
+	 * */
+	public function import( Request $request,Model $Model,Custom $Custom,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct, FilesManager $FilesManager){
+		// 接口验签
+		$this->verify_sign();
+		// 验证参数
+		$request->scene('create')->validate();
+		// 返回结果
+		return						json_send(['code'=>'success','msg'=>'同步成功','data'=>[]]);
+	}
+
+
+}

+ 85 - 0
app/Http/Controllers/Api/WorkBind.php

@@ -0,0 +1,85 @@
+<?php namespace App\Http\Controllers\Api;
+
+use App\Facades\Servers\WechatWork\ExternalContact;
+use App\Http\Controllers\Api\Api;
+use App\Models\Custom as Model;
+use App\Models\Work\External as WorkExternal;
+use App\Models\Work\User as WorkUser;
+use Vinkla\Hashids\Facades\Hashids;
+use App\Facades\Servers\WechatMini\Mini;
+use App\Http\Requests\Api\WorkBind as Request;
+
+/**
+ * 企微绑定
+ * 
+ * @author 刘相欣
+ * 
+ * */
+class WorkBind extends Api{
+
+	/**
+	 * 绑定客户			/api/work_bind/custom
+	 * 
+	 * @param	string		$code		授权码
+	 * 
+	 * */
+	public function custom(Request $request,Model $Model,WorkExternal $WorkExternal,WorkUser $WorkUser){
+		// 接口验签
+		// $this->verify_sign();
+		// 参数验证
+		$request->scene('custom')->validate();
+		// 检查登录
+		$code							= request('code','');
+		$id								= request('kailin_uid','');
+		$workUserId						= request('work_userid','');
+		// 解析ID
+		$id                            	= Hashids::decodeHex($id);
+		// 用户不存在
+		if( empty($id) )			    return json_send(['code'=>'error','msg'=>'用户不存在','data'=>['error'=>'用户ID有误']]);
+		// // 授权结果
+		$userPhone						= Mini::getUserPhone($code);
+		// // 如果所需字段不存在
+		if( isset($userPhone['error']) ) return json_send(['code'=>'error','msg'=>'授权失败','data'=>['error'=>$userPhone['error']]]);
+		// // 如果所需字段不存在
+		if( empty($userPhone['purePhoneNumber']) ) return json_send(['code'=>'error','msg'=>'未获取到手机号','data'=>['error'=>'未获取到手机号']]);
+		// 查询用户
+		$external						= $WorkExternal->getOne($id);
+		// 用户不存在
+		if( empty($external) )			return json_send(['code'=>'error','msg'=>'用户不存在','data'=>['error'=>'用户不存在']]);
+        // 如果手机号已经存在
+        if( $external['custom_uid'] )   return json_send(['code'=>'error','msg'=>'用户已绑定','data'=>['error'=>'用户已绑定']]);
+		// 获取不包含区号的手机号(因为绑定手机号字段会有国际区号)
+		$phone							= $userPhone['purePhoneNumber'];
+		// 通过手机号查询账号
+		$custom 						= $Model->getOneByPhone($phone);
+		// 新用户信息
+		$newCustom						= ['phone'=>$phone,'external_userid'=>$external['external_userid'],'userpic'=>$external['avatar'],'username'=>$external['name'],'sex'=>$external['gender'],'user_type'=>$external['user_type']];
+		// 修改客户信息
+		if( $custom )					$Model->edit($custom['uid'],$newCustom);
+		// 添加客户信息
+		$uid 							= $custom ? $custom['uid'] : $Model->add($newCustom);
+		// 没有手机号对应的账号
+		if( !$uid )						return json_send(['code'=>'error','msg'=>'手机号注册失败','data'=>['error'=>'手机号注册失败']]);
+		// 查询对应的跟进人员
+		$followUser						= $WorkUser->getOneByExtUserId($external['external_userid'],$workUserId);
+		// 如果没有跟进人员
+		if( !$followUser )				$followUser = ['work_userid'=>$workUserId,'external_userid'=>$external['external_userid']];
+		// 备注手机号格式转数组并追加新手机号
+		$remarkMobiles					= push_str_arr($followUser['remark_mobiles'],$phone);
+		// 添加备注手机号
+		ExternalContact::remark($external['external_userid'],$workUserId,['remark_mobiles'=>$remarkMobiles]);
+		// 修改信息
+		$result						    = $WorkExternal->edit($id,['custom_uid'=>$uid]);
+        // 绑定失败
+        if( !$result )                  return json_send(['code'=>'error','msg'=>'绑定失败','data'=>['error'=>'绑定失败']]);
+		// 转字符串
+		$followUser['remark_mobiles']	= implode(',',$remarkMobiles);
+		// 修改或者添加跟进人员客户画像
+		empty($followUser['id']) ? $WorkUser->add($followUser) : $WorkUser->edit($followUser['id'],$followUser);
+		// 进行登录
+		$token							= $Model->createLoginAuthcode($uid,time());
+		// 返回结果
+		return							json_send(['code'=>'success','msg'=>'登录成功','data'=>$token]);
+	}
+
+}

+ 168 - 0
app/Http/Controllers/Controller.php

@@ -0,0 +1,168 @@
+<?php namespace App\Http\Controllers;
+
+// 队列服务
+use Illuminate\Foundation\Bus\DispatchesJobs;
+// 验证请求
+use Illuminate\Foundation\Validation\ValidatesRequests;
+// 基础控制器
+use Illuminate\Routing\Controller as BaseController;
+// 配置模型
+use App\Models\Config;
+// 视图工厂
+use Illuminate\Contracts\View\Factory as ViewFactory;
+/**
+ * 控制器总控
+ * 
+ */
+class Controller extends BaseController
+{
+    use DispatchesJobs, ValidatesRequests;
+
+	// 模板变量
+	protected  	$bladeData = [];
+
+    /**
+	 * 构造方法,初始化
+	 * 
+	 * */
+	public function __construct(){
+		// 初始化
+		if( method_exists($this, '_initialize') ) $this->_initialize();
+		// 初始化
+		if( method_exists($this, '__init') ) $this->__init();
+		// 读取配置
+        $config = $this->loadConfig();
+		// 动态配置
+        config($config);
+	}
+
+	/* 初始化 */
+	protected function _initialize(){
+        
+    }
+
+	/* 初始化 */
+	protected function __init(){
+        
+    }
+
+    /* 读取配置 */
+	protected function loadConfig(){
+        // 返回配置
+        return (new Config)->getConfigList();
+    }
+
+	/**
+     * 操作错误跳转的快捷方法
+     * @param  Mixed     $msg 提示信息
+     * @param  String    $url 跳转的URL地址
+     * @param  Int   $wait 跳转等待时间
+	 * 
+     * @return Void
+     */
+    protected function error($msg = '', $url = null, $wait = 3)
+	{
+		if ( is_null($url) ) {
+            $url = request()->ajax() ? '' : 'javascript:history.back(-1);';
+        } elseif ('' !== $url) {
+            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : url($url);
+        }
+		// 返回结果
+		return		view('error',['msg'=>$msg,'url'=>$url,'wait'=>$wait]);
+	}
+
+
+	/**
+     * 获取视图内容
+     *
+     * @param  string|null  $view
+     * @param  \Illuminate\Contracts\Support\Arrayable|array  $data
+     * @param  array  $mergeData
+     * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
+     */
+    protected function fetch($view = null, $data = [], $mergeData = [])
+    {
+		// 如果没有指定路径使用对应模板路径
+		if (!$view)		$view = $this->getBladePath();
+		// 如果有数据
+		if( $data )		$this->bladeData = array_merge($this->bladeData,$data);
+		// 获取所有模板变量
+		$data			= $this->bladeData;
+		// 获取工厂类
+        $factory 		= app(ViewFactory::class);
+        // 创建视图内容并返回
+        return			$factory->make($view, $data, $mergeData);
+    }
+
+	/**
+     * 模板变量赋值
+     * @access protected
+     * @param  mixed $name  要显示的模板变量
+     * @param  mixed $value 变量的值
+     * @return $this
+     */
+    protected function assign( $name, $value = '')
+    {
+		// 如果是数组
+        if( is_array($name) ){
+			// 合并数据
+			$this->bladeData = array_merge($this->bladeData,$name);
+		}else{
+			// 否则增加或者更新
+			$this->bladeData[$name] = $value;
+		}
+		// 返回结果
+        return $this->bladeData;
+    }
+
+	/**
+     * 获取模板文件路径
+	 * 
+     */
+    protected function getBladePath()
+    {
+		// 获取当前请求的控制器命名空间以及方法
+		$actionName 			= request()->route()->getActionName();
+		// 切割成控制器路径和方法
+		list($class, $method)	= explode('@',$actionName);
+		/* 获取模块名 */
+		// 以反斜杠切割成数组
+		$modules				= implode('\\', array_slice(explode('\\', $class), 0, -1));
+		// 去除斜杠
+		$modules				= trim($modules,'\\');
+		// 替换掉数据
+		$modules				= str_replace('App\\Http\\Controllers\\','',$modules);
+        // 模块名
+        $modules				= str_replace('\\','/',$modules);
+        // 控制器名称
+        $controller				= str_replace('Controller','',substr(strrchr($class, '\\'), 1));
+		// 转下划线格式
+		$controller				= $this->humpToSnake($controller);
+		// 模板路径
+		$bladePath				= implode('.',[$modules,$controller,$method]);
+		// 全转小写
+		$bladePath				= strtolower($bladePath);
+		// 返回结果
+		return 					$bladePath;
+    }
+
+	/**
+	 * 驼峰转下划线
+	 * 
+	 */
+	protected function humpToSnake($camelCaps,$separator='_')
+    {
+        return  strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
+    }
+
+	/**
+	 * 驼峰转下划线
+	 * 
+	 */
+	protected function snakeToHump($camelCaps,$separator='_')
+    {
+        return  strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
+    }
+
+
+}

+ 78 - 0
app/Http/Kernel.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Http;
+
+use Illuminate\Foundation\Http\Kernel as HttpKernel;
+/**
+ * Http请求核心
+ * @property  Array   $middleware           全局中间件
+ * @property  Array   $middlewareGroups     中间分组
+ * @property  Array   $routeMiddleware      路由中间件
+ * 
+ */
+class Kernel extends HttpKernel
+{
+    /**
+     * 全局HTTP中间件堆栈
+     *
+     * 这些中间件在应用程序的每个请求期间都会运行.
+     *
+     * @var array
+     */
+    protected $middleware = [
+        // 获取应该信任的主机
+       // \App\Http\Middleware\TrustHosts::class,
+        // 关于设置信任代理有关的中间件
+        //\App\Http\Middleware\TrustProxies::class,
+        // 设置跨域请求  config/cors.php 可配置
+        \Fruitcake\Cors\HandleCors::class,
+        // post数据大小
+        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
+        // 修剪字符串
+        \App\Http\Middleware\TrimStrings::class,
+        // 将空字符串字段转换为 null
+        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
+        // 读取语言环境
+        \App\Http\Middleware\LoadLocale::class,
+    ];
+
+    /**
+     * 应用程序的路由中间件组
+     *
+     * 这些中间件在应用程序的每个路由分组请求期间都会运行.
+     * @var array
+     */
+    protected $middlewareGroups = [
+        /* web请求 */
+        'web' => [
+            // cookies加密
+            \App\Http\Middleware\EncryptCookies::class,
+            // 队列cookie到响应
+            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+            // 使用session 注意 一定要在cookie加密之后
+            \Illuminate\Session\Middleware\StartSession::class,
+            // CSRF 保护 注意 一定要在session开始之后
+            \App\Http\Middleware\VerifyCsrfToken::class,
+            // 替换绑定
+            \Illuminate\Routing\Middleware\SubstituteBindings::class,
+        ],
+        /* 接口请求 */
+        'api' => [
+            // 替换绑定
+            \Illuminate\Routing\Middleware\SubstituteBindings::class,
+            // 验证请求签名
+        ],
+    ];
+
+    /**
+     * 应用程序的路由中间件
+     *
+     * 这些中间件可以分配给组或单独使用
+     *
+     * @var array
+     */
+    protected $routeMiddleware = [
+        // 后端登录验证
+        'admin'=>\App\Http\Middleware\AdminAuth::class,
+    ];
+}

+ 204 - 0
app/Http/Middleware/AdminAuth.php

@@ -0,0 +1,204 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+class AdminAuth
+{
+    // 无需验证的路径
+    protected   $except     = [
+                                'admin/login/index',
+                                'admin/login/send_code',
+                                'admin/login/out',
+                                'admin/files_manager/add',      // 文件上传
+                                'admin/contact_way/part_user',  // 接待人员
+                                'admin/product/get_spec_html',       // 获取类型下的规格
+                            ];
+    //默认配置
+    protected   $_config    = [
+                                'auth_on'           => true, // 认证开关
+                                'auth_type'         => 1, // 认证方式,1为实时认证;2为登录认证。
+                                'auth_group'        => 'auth_group', // 用户组数据表名
+                                'auth_group_access' => 'auth_group_access', // 用户-用户组关系表
+                                'auth_rule'         => 'auth_rule' // 权限规则表     
+                            ];
+    /**
+	 * $prefix表前缀
+	 */
+    public function __construct()
+    {
+        // 判断配置
+        if ( config('AUTH_CONFIG') )        {
+            //可设置配置项 AUTH_CONFIG, 此配置项为数组。
+            $this->_config                  = array_merge($this->_config, config('AUTH_CONFIG'));
+        }
+    }
+
+
+
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle(Request $request, Closure $next)
+    {
+        // 当前路径
+        $path  = ltrim($request->getPathInfo(), '/');
+        // 判断是否需要验证登录
+        if (!in_array($path, $this->except)) {
+            // 如果没有登录,重定向到登录页
+            if ( !admin('uid'))  $this->unLogin($request);
+            // 如果不是超级管理员
+            if ( !in_array(admin('uid'), explode(',', config('administrator'))) ) {
+                // 进行验证
+                if ( !$this->check($path, admin('uid')) )  $this->noAuth('没有权限!');
+            }
+        }
+        // 追加入
+        $request['authRules'] =  $this->getAuthList(admin('uid'),1);
+        // 返回下一个闭包
+        return  $next($request);
+    }
+
+    /**
+     * Handle an unauthenticated user.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return void
+     *
+     * @throws AdminAuthException
+     */
+    protected function unLogin($request)
+    {
+        throw new \App\Exceptions\Admin\AuthException('请先登录',$this->redirectTo($request),0);
+    }
+
+    /**
+     * Handle an unauthenticated user.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return void
+     *
+     * @throws AdminAuthException
+     */
+    protected function noAuth($msg,$url='',$wait=3)
+    {
+        throw new \App\Exceptions\Admin\AuthException($msg,$url,$wait);
+    }
+
+    /**
+     * Get the path the user should be redirected to when they are not authenticated.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return string|null
+     */
+    protected function redirectTo($request)
+    {
+        if (!$request->expectsJson()) return route('login');
+    }
+
+    /**
+     * 检查权限
+     * @param name string|array  需要验证的规则列表
+     * @param uid  int           认证用户的id
+     * @return boolean           通过验证返回true;失败返回false
+     */
+    public function check($path, $uid, $type = 1)
+    {	
+        // 未开启验证,直接通过
+        if ( !$this->_config['auth_on'] )   return true;
+        // 获取用户需要验证的所有有效规则列表
+        $authList                           = $this->getAuthList($uid, $type); 
+       
+        // 切割path
+        $path                               = explode('/', $path);
+        // 没有控制器
+        if( count($path) < 2 )              $path[] = 'index';
+        // 没有方法
+        if( count($path) < 3 )              $path[] = 'index';
+        // 切割path
+        $path                               = implode('/', $path);
+        // 判断是否通过验证
+        return                              in_array($path, $authList);
+    }
+
+    /**
+     * 根据用户id获取用户组,返回值为数组
+     * @param  int      $uid        用户id
+     * @return array                用户所属的用户组
+     */
+    public function getGroups($uid)
+    {
+        // 用户组
+        static                          $groups = [];
+        // 存在小组,返回
+        if ( isset($groups[$uid]) )     return $groups[$uid];
+        // 从数据库查询
+        $userrGroups                    = DB::table($this->_config['auth_group_access'])
+                                            ->where([[$this->_config['auth_group_access'].'.user_uid','=',$uid],[$this->_config['auth_group'].'.status','=',1]])
+                                            ->join( $this->_config['auth_group'], $this->_config['auth_group_access'].'.group_id','=',$this->_config['auth_group'].'.id')
+                                            ->select(['user_uid as uid','group_id','title','rules'])->get()->toArray();
+        // 获取对应用户的权限组
+        $groups[$uid]                   = $userrGroups ?: [];
+        // 返回用户的权限组
+        return                          $groups[$uid];
+    }
+
+    /**
+     * 获得权限列表
+     * @param integer $uid  用户id
+     * @param integer $type
+     */
+    protected function getAuthList($uid, $type)
+    {
+       
+        // 保存用户验证通过的权限列表
+        static $_authList                   = [];
+        // 验证类型
+        $key                                = $uid .'_t_'.implode(',', (array) $type);
+        // 已经存在权限列表,直接返回
+        if (isset($_authList[$key]))   return $_authList[$key];
+        // 验证类型,如果不是实时验证
+        if ( $this->_config['auth_type'] == 2 ) {
+            // 从session读取验证列表
+        	$session                        = session('_AUTH_LIST_'.$key);
+            // 存在则返回
+        	if( !empty($session) )          return $session;
+        }
+        // 读取用户所属用户组
+        $groups                             = $this->getGroups($uid);
+        // 保存用户所属用户组设置的所有权限规则id
+        $ids                                = [];
+        // 获取字段值
+        $ids                                = array_column($groups,'rules');
+        // 合并字符值
+        $ids                                = array_unique(array_filter(explode(',',implode(',',$ids))));
+        // 为空
+        if( empty($ids) )                   return [];
+        // 读取用户组所有权限规则
+        $rules                              = Db::table($this->_config['auth_rule'])->whereIn('menu_id',$ids)->pluck('name')->toArray();
+         // 循环转大写
+        foreach ( $rules as $rule ) {
+            // 转小写,截除左边斜杠
+            $rules[]                        = ltrim(strtolower($rule),'/');
+        }
+        // 去重
+        $rules                              = array_unique($rules);
+        // 如果是登录验证
+        if ($this->_config['auth_type'] == 2 ) {
+            // 用户验证列表
+            $rules[$key]                    = $rules;
+            //规则列表结果保存到session
+            session('_AUTH_LIST_'.$key,$rules);
+        }
+        //  返回结果
+        return                              $rules;
+    }
+
+}

+ 21 - 0
app/Http/Middleware/Authenticate.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Auth\Middleware\Authenticate as Middleware;
+
+class Authenticate extends Middleware
+{
+    /**
+     * 获取用户未通过身份验证时应重定向到的路径。
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return string|null
+     */
+    protected function redirectTo($request)
+    {
+        if (! $request->expectsJson()) {
+            return route('login');
+        }
+    }
+}

+ 22 - 0
app/Http/Middleware/EncryptCookies.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
+
+
+/**
+ * Cookies加密
+ */
+class EncryptCookies extends Middleware
+{
+
+    /**
+     * 不应加密的Cookie的名称
+     *
+     * @var array
+     */
+    protected $except = [
+        //
+    ];
+}

+ 68 - 0
app/Http/Middleware/LoadLocale.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\App;
+
+/**
+ * 读取语言环境
+ * 
+ */
+class LoadLocale
+{
+    /**
+     * 处理传入请求
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle(Request $request, Closure $next)
+    {
+        // 设置语言
+        $request    = $this->setLocale($request);
+        // 返回结果
+        return      $next($request);
+    }
+    
+    /**
+     * 自动侦测当前语言
+     * @param  \Illuminate\Http\Request  $request
+     */
+    private function setLocale(Request $request){
+        // 默认语言
+        $langSet = config('lang.default_lang','en');
+        // 多语言自动侦测变量名
+        if ($request->get(config('lang.detect_var','lang'))) {
+            // url中设置了语言变量
+            $langSet = strtolower($request->get(config('lang.detect_var','lang')));
+        } elseif ($request->header(config('lang.header_var','lang'))) {
+            // Header中设置了语言变量
+            $langSet = strtolower($request->header(config('lang.header_var','lang')));
+            
+        } elseif ($request->cookie(config('lang.cookie_var','lang'))) {
+            // Cookie中设置了语言变量
+            $langSet = strtolower($request->cookie(config('lang.cookie_var','lang')));
+        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
+            // 自动侦测浏览器语言
+            $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
+            // 如果有匹配语言,获取第一条语言
+            if ($match)  $langSet = strtolower($matches[1]);
+        }
+        // 统一分割符号
+        $langSet         = str_ireplace('_','-',$langSet);
+        // 允许语言列表
+        $allow_lang_list = config('lang.allow_lang_list');
+        // 如果不在允许语言内,使用默认语言
+        if( !empty($allow_lang_list) && !in_array($langSet,$allow_lang_list) ) $langSet = config('lang.default_lang','en');
+        // 请求语言设置为最终语言
+        $request->lang   = $langSet;
+        // 设置语言
+        App::setLocale($langSet);
+        // 返回结果
+        return $request;
+    }
+
+
+}

+ 17 - 0
app/Http/Middleware/PreventRequestsDuringMaintenance.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
+
+class PreventRequestsDuringMaintenance extends Middleware
+{
+    /**
+     * 启用维护模式时应可访问的URI。
+     *
+     * @var array
+     */
+    protected $except = [
+        //
+    ];
+}

+ 32 - 0
app/Http/Middleware/RedirectIfAuthenticated.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use App\Providers\RouteServiceProvider;
+use Closure;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class RedirectIfAuthenticated
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @param  string|null  ...$guards
+     * @return mixed
+     */
+    public function handle(Request $request, Closure $next, ...$guards)
+    {
+        $guards = empty($guards) ? [null] : $guards;
+
+        foreach ($guards as $guard) {
+            if (Auth::guard($guard)->check()) {
+                return redirect(RouteServiceProvider::HOME);
+            }
+        }
+
+        return $next($request);
+    }
+}

+ 23 - 0
app/Http/Middleware/TrimStrings.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
+
+// 修剪字符串
+class TrimStrings extends Middleware
+{
+    /**
+     * 不应修剪的属性的名称。
+     *
+     * @var array
+     */
+    protected $except = [
+        // 密码空格不做修剪
+        'current_password',
+        'password',
+        'password_confirmation',
+        // 兼容App端 创建订单时候,终端名称误带后缀空格倒是签名失败
+        'client',
+    ];
+}

+ 20 - 0
app/Http/Middleware/TrustHosts.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Http\Middleware\TrustHosts as Middleware;
+
+class TrustHosts extends Middleware
+{
+    /**
+     * 获取应该信任的主机模式
+     *
+     * @return array
+     */
+    public function hosts()
+    {
+        return [
+            $this->allSubdomainsOfApplicationUrl(),
+        ];
+    }
+}

+ 24 - 0
app/Http/Middleware/TrustProxies.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Fideloper\Proxy\TrustProxies as Middleware;
+use Illuminate\Http\Request;
+
+// 关于设置信任代理有关的中间件
+class TrustProxies extends Middleware
+{
+    /**
+     * 此应用程序的受信任代理。
+     *
+     * @var array|string|null
+     */
+    protected $proxies;
+
+    /**
+     * 应用于检测代理的标头(headers)
+     *
+     * @var int
+     */
+    protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;
+}

+ 35 - 0
app/Http/Middleware/VerifyCsrfToken.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
+
+/**
+ * CSRF 保护
+ * 防止跨站请求伪造(CSRF)攻击
+ * 
+ */
+class VerifyCsrfToken extends Middleware
+{
+    /**
+     * 应从CSRF验证中排除的URI
+     *
+     * @var array
+     */
+    protected $except = [
+        // 接待人员
+        'admin/contact_way/part_user',
+        // 文件管理-添加文件
+        'admin/files_manager/add',
+        // 图片管理
+        'admin/image_manager/upload',
+        // 图片管理
+        'admin/image_manager/folder',
+        // 图片管理
+        'admin/image_manager/delete',
+        // 编辑器
+        'admin/ueditor/upload',
+        // 导入表格
+        'admin/orders/import_execl'
+    ];
+}

+ 72 - 0
app/Http/Requests/Admin/AdminUser.php

@@ -0,0 +1,72 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+use Illuminate\Validation\Rule;
+
+/**
+ * 管理验证器
+ * 
+ */
+class AdminUser extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 编辑时排除ID 
+        $id			= request('uid',null);
+		// 非重规则
+		$unique  	= Rule::unique('admin')->where(function ($query) {
+						return $query->where(['username'=>request('username','')]);
+					})->ignore($id,'uid');
+        // 非重规则phone
+		$uniphone  	= Rule::unique('admin')->where(function ($query){
+                        return $query->where(['phone'=>request('phone','')]);
+                    })->ignore($id,'uid');
+        // 编辑时排除ID 
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'username' 			=> ['required',$unique],
+            'phone'		        => ['required','regex:/^1[3456789][0-9]{9}$/',$uniphone],
+           'password'		    => 'required',
+	        'uid'               => 'required|integer|gt:0',
+            'groups'            => 'required'
+        ];
+    }
+
+    
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['username','phone','password','groups'],
+        'edit'  		        => ['uid','username','phone'],
+        'del'  		            => ['uid'],
+        'set_status'  		    => ['uid'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'username.required' =>  '用户名必填',
+            'username.unique'	=>  '用户名已经存在',
+            'phone.required'    =>  '手机号必填',
+            'phone.regex'  	    =>  '手机号格式错误',  
+            'phone.unique'	    =>  '手机号已经存在',
+            'password.required'	=>  '密码必填',
+            'uid.required'      => 'ID未知',
+            'uid.integer'   	=> 'ID格式错误',
+            'uid.gt'   		    => 'ID格式错误',
+            'groups.required'   => '用户组必选'
+        ];
+    }
+    
+}

+ 56 - 0
app/Http/Requests/Admin/AuthManager.php

@@ -0,0 +1,56 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 权限管理验证器
+ * 
+ */
+class AuthManager extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 编辑时排除ID 
+        $id = request('id',0);
+        // 返回结果
+        return [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'title' 			=> 'required|unique:auth_group,title,'.$id,
+	        'id'                => 'required|integer|gt:0',
+            'group_pid'         => 'required',
+        ];
+    }
+
+    // 场景列表
+    protected $scenes = [
+		'add'  		            => ['title','group_pid'],
+        'edit'  		        => ['id','title','group_pid'],
+        'del'  		            => ['id'],
+        'access'  		        => ['id'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'title.required'  			=> '用户组必填',
+	        'title.unique'   			=> '用户组已存在',
+            'id.required'   		    => 'ID未知',
+            'id.integer'   		        => 'ID格式错误',
+            'id.gt'   		            => 'ID格式错误',
+            'group_pid.required'        => '上级必选'
+        ];
+    }
+    
+}

+ 49 - 0
app/Http/Requests/Admin/Banner.php

@@ -0,0 +1,49 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 类型验证器
+ * 
+ */
+class Banner extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'name' 			    => 'required',
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+    
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['name'],
+        'edit'  		        => ['id','name'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'name.required'     => '名称必填',
+            'id.required'       => 'ID未知',
+            'id.integer'        => 'ID格式错误',
+            'id.gt'   		    => 'ID格式错误',
+        ];
+    }
+    
+}

+ 56 - 0
app/Http/Requests/Admin/Business.php

@@ -0,0 +1,56 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+use Illuminate\Validation\Rule;
+
+/**
+ * 商业公司验证器
+ * 
+ */
+class Business extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+	        'name' 			    => 'required|unique:business,name,'.request('id',0),
+            'phone'		        => ['required','regex:/^1[3456789][0-9]{9}$/'],
+	        'id'                => 'required|integer|gt:0',
+        ];
+    }
+
+    
+    // 场景列表
+    protected   $scenes         = [
+		'add'  		            => ['name','phone'],
+        'edit'  		        => ['id','name','phone'],
+        'set_status'  		    => ['id'],
+	];
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            'name.required'     => '公司名称必填',
+            'name.unique'	    => '公司名称已经存在',
+            'phone.required'    => '联系方式必填',
+            'phone.regex'  	    => '联系方式格式错误',  
+            'phone.unique'	    => '联系方式已经存在',
+            'id.required'       => 'ID未知',
+            'id.integer'        => 'ID格式错误',
+            'id.gt'   		    => 'ID格式错误',
+        ];
+    }
+    
+}

+ 43 - 0
app/Http/Requests/Admin/Config.php

@@ -0,0 +1,43 @@
+<?php namespace App\Http\Requests\Admin;
+
+use App\Http\Requests\BaseRequest;
+
+/**
+ * 配置验证器
+ * 
+ */
+class Config extends BaseRequest
+{
+    /**
+     * 获取应用于请求的规则
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        // 返回结果
+        return      [
+            // 有时候我们希望某个字段在第一次验证失败后就停止运行验证规则,只需要将 bail 添加到规则中:
+            // 验证字段,验证规则,提示信息
+        ];
+    }
+
+    // 场景列表
+    protected   $scenes         = [
+
+	];
+    
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array
+     */
+    public function messages()
+    {
+        return [
+            
+        ];
+    }
+
+}

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