one_after 3 kuukautta sitten
vanhempi
commit
bd29d6ed78
100 muutettua tiedostoa jossa 19950 lisäystä ja 0 poistoa
  1. 9 0
      404.html
  2. 21 0
      LICENSE
  3. 74 0
      app/business/BankCardBusiness.php
  4. 46 0
      app/business/CheckInBusiness.php
  5. 436 0
      app/business/GoodsBusiness.php
  6. 102 0
      app/business/LoginBusiness.php
  7. 55 0
      app/business/PayFiveBusiness.php
  8. 59 0
      app/business/PayThreeBusiness.php
  9. 55 0
      app/business/PayTwoBusiness.php
  10. 706 0
      app/business/PayorderBusiness.php
  11. 36 0
      app/business/SmsBusiness.php
  12. 80 0
      app/business/StreamBusiness.php
  13. 104 0
      app/business/TaskBusiness.php
  14. 36 0
      app/business/UserBusiness.php
  15. 130 0
      app/business/UserIdentityBusiness.php
  16. 186 0
      app/business/WithdrawBusiness.php
  17. 136 0
      app/controller/AddressController.php
  18. 249 0
      app/controller/BankCardController.php
  19. 173 0
      app/controller/BindingController.php
  20. 140 0
      app/controller/ConfigController.php
  21. 673 0
      app/controller/GoodsController.php
  22. 66 0
      app/controller/IssueController.php
  23. 316 0
      app/controller/LoginController.php
  24. 148 0
      app/controller/MyGoodsController.php
  25. 95 0
      app/controller/PayController.php
  26. 178 0
      app/controller/RaffleController.php
  27. 122 0
      app/controller/RepaymenController.php
  28. 71 0
      app/controller/StreamController.php
  29. 170 0
      app/controller/UploadController.php
  30. 461 0
      app/controller/UserController.php
  31. 53 0
      app/controller/UserIdentityController.php
  32. 97 0
      app/controller/WithdrawController.php
  33. 419 0
      app/functions.php
  34. 71 0
      app/middleware/Decrypt.php
  35. 83 0
      app/middleware/Sign.php
  36. 42 0
      app/middleware/StaticFile.php
  37. 72 0
      app/middleware/UserToken.php
  38. 29 0
      app/model/Test.php
  39. 400 0
      app/route.php
  40. 21 0
      app/view/404.html
  41. 9 0
      app/view/4041.html
  42. 14 0
      app/view/index/view.html
  43. 75 0
      composer.json
  44. 6418 0
      composer.lock
  45. 25 0
      config/app.php
  46. 21 0
      config/autoload.php
  47. 18 0
      config/bootstrap.php
  48. 15 0
      config/container.php
  49. 35 0
      config/database.php
  50. 15 0
      config/dependence.php
  51. 5 0
      config/event.php
  52. 17 0
      config/exception.php
  53. 149 0
      config/log.php
  54. 15 0
      config/middleware.php
  55. 100 0
      config/plugin/hg/apidoc/app.php
  56. 3 0
      config/plugin/hg/apidoc/route.php
  57. 24 0
      config/plugin/webman/console/app.php
  58. 4 0
      config/plugin/webman/event/app.php
  59. 17 0
      config/plugin/webman/event/bootstrap.php
  60. 7 0
      config/plugin/webman/event/command.php
  61. 57 0
      config/process.php
  62. 22 0
      config/redis.php
  63. 29 0
      config/route.php
  64. 31 0
      config/server.php
  65. 65 0
      config/session.php
  66. 23 0
      config/static.php
  67. 25 0
      config/translation.php
  68. 22 0
      config/view.php
  69. 24 0
      env.txt
  70. 39 0
      index.html
  71. 127 0
      plugin/admin/api/Auth.php
  72. 93 0
      plugin/admin/api/Install.php
  73. 150 0
      plugin/admin/api/Menu.php
  74. 55 0
      plugin/admin/api/Middleware.php
  75. 79 0
      plugin/admin/app/common/Auth.php
  76. 1165 0
      plugin/admin/app/common/Layui.php
  77. 193 0
      plugin/admin/app/common/Tree.php
  78. 567 0
      plugin/admin/app/common/Util.php
  79. 260 0
      plugin/admin/app/controller/AccountController.php
  80. 269 0
      plugin/admin/app/controller/AdminController.php
  81. 254 0
      plugin/admin/app/controller/ApplyRecordController.php
  82. 68 0
      plugin/admin/app/controller/ArticleController.php
  83. 76 0
      plugin/admin/app/controller/ArticleTypeController.php
  84. 68 0
      plugin/admin/app/controller/BankCardController.php
  85. 67 0
      plugin/admin/app/controller/Base.php
  86. 85 0
      plugin/admin/app/controller/CheckInController.php
  87. 148 0
      plugin/admin/app/controller/ConfigController.php
  88. 456 0
      plugin/admin/app/controller/Crud.php
  89. 24 0
      plugin/admin/app/controller/DevController.php
  90. 111 0
      plugin/admin/app/controller/DictController.php
  91. 85 0
      plugin/admin/app/controller/GoodController.php
  92. 202 0
      plugin/admin/app/controller/IndexController.php
  93. 392 0
      plugin/admin/app/controller/InstallController.php
  94. 68 0
      plugin/admin/app/controller/InviteController.php
  95. 243 0
      plugin/admin/app/controller/MyGoodController.php
  96. 68 0
      plugin/admin/app/controller/PayAisleController.php
  97. 217 0
      plugin/admin/app/controller/PayorderController.php
  98. 549 0
      plugin/admin/app/controller/PluginController.php
  99. 68 0
      plugin/admin/app/controller/RaffleController.php
  100. 0 0
      plugin/admin/app/controller/RaffleLogController.php

+ 9 - 0
404.html

@@ -0,0 +1,9 @@
+
+<html>
+<head><title>404 Not Found</title></head>
+<body>
+<center><h1>404 Not Found</h1></center>
+<hr><center>nginx</center>
+</body>
+</html>
+        

+ 21 - 0
LICENSE

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

+ 74 - 0
app/business/BankCardBusiness.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Redis;
+
+class BankCardBusiness
+{
+    /** 用户卡号信息
+     * @param array $param
+     * @return void
+     */
+    static public function data(array $param)
+    {
+        $data=Db::table('wa_bank_card')->where(function ($query)use ($param){
+            if(Arr::get($param,'uid')){
+                $query->where('uid',$param['uid']);
+            }
+        })->first();
+        return $data;
+    }
+
+    /**绑定和修改实名信息
+     * @param array $param
+     * @return void
+     */
+    static public function UpData(array $param)
+    {
+        try {
+
+            $data=Db::table('wa_bank_card')->where('uid',$param['user_data']['id'])->first();
+            $user_identity_name=Db::table('wa_user_identity')->where('uid',$param['user_data']['id'])->value('name');
+            if(empty($user_identity_name)){
+                throw new \Exception('请先实名!');
+            }
+            if($user_identity_name != $param['account_holder']){
+                throw new \Exception('实名人和开户人不一致,请绑定实名人的银行卡!');
+            }
+            if(empty($data)){
+
+                /** 绑定 */
+                Db::table('wa_bank_card')->insert([
+                    'affiliated_bank'       =>$param['affiliated_bank'],
+                    'account_holder'        =>$param['account_holder'],
+                    'card_number'           =>$param['card_number'],
+                    'uid'                   =>$param['user_data']['id'],
+                    'created_at'            =>date('Y-m-d H:i:s'),
+                    'updated_at'            =>date('Y-m-d H:i:s'),
+                ]);
+            }else{
+                throw new \Exception('请联系客服进行修改!');
+                if($user_identity_name != $param['account_holder']){
+                    throw new \Exception('实名人和开户人不一致,请绑定实名人的银行卡!');
+                }
+                /** 修改 */
+                Db::table('wa_bank_card')->where('uid',$param['user_data']['id'])->update([
+                    'affiliated_bank'       =>$param['affiliated_bank'],
+                    'account_holder'        =>$param['account_holder'],
+                    'card_number'           =>$param['card_number'],
+                    'o_affiliated_bank'     =>$data->affiliated_bank,
+                    'o_account_holder'      =>$data->account_holder,
+                    'o_card_number'         =>$data->o_card_number,
+                    'created_at'            =>date('Y-m-d H:i:s'),
+                    'updated_at'            =>date('Y-m-d H:i:s'),
+                ]);
+            }
+        }catch (\Throwable $exception){
+            throw new \Exception($exception->getMessage());
+        }
+        return true;
+    }
+}

+ 46 - 0
app/business/CheckInBusiness.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+
+class CheckInBusiness
+{
+    /**通过
+     * @param $id
+     * @return void
+     */
+   static public function pass($id)
+    {
+        try {
+            $data=Db::table('wa_check_in')->where('id',$id)->first();
+            if($data->status != 1){
+                throw new \Exception('当前订单已处理!');
+            }
+            StreamBusiness::addStream($data->user_id,$data->money,streamType12,moldType2,moldTypefild2,$id);
+            Db::table('wa_check_in')->where('id',$id)->update(['status'=>2]);
+        }catch (\Throwable $exception){
+            throw new \Exception($exception->getMessage());
+        }
+    }
+    /** 驳回
+     * @param $id
+     * @return void
+     * @throws \Exception
+     */
+    static public function reject($id)
+    {
+        try {
+            $data=Db::table('wa_check_in')->where('id',$id)->first();
+            if($data->status != 1){
+                throw new \Exception('当前订单已处理!');
+            }
+            Db::table('wa_check_in')->where('id',$id)->update(['status'=>3]);
+        }catch (\Throwable $exception){
+            throw new \Exception($exception->getMessage());
+        }
+
+    }
+
+}

+ 436 - 0
app/business/GoodsBusiness.php

@@ -0,0 +1,436 @@
+<?php
+
+    namespace app\business;
+
+    use Illuminate\Support\Arr;
+    use support\Db;
+    use support\Log;
+    use support\Redis;
+    use yzh52521\EasyHttp\Http;
+
+    class GoodsBusiness
+    {
+
+        /**购买慈善项目
+         * @return void
+         */
+        static public function buyType1(array $param)
+        {
+            try {
+                $payorderId = PayorderBusiness::orderAdd($param);
+
+                $payorder = Db::table('wa_payorder')->where('id', $payorderId)->first();
+
+//                if ($payorder->pay_type == 1) {
+//                    throw new \Exception('通道未开通!');
+//                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('拉丁支付', $data);
+//                    if (Arr::get($data, 'data.code') != 200) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                } elseif ($payorder->pay_type == 2) {
+//                    $data = PayTwoBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('桥头支付支付', $data);
+//                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+//                        throw new \Exception('调用支付失败!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 3) {
+//                    $data = PayThreeBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('林北支付支付', $data);
+//                    if (Arr::get($data, 'data.code') != 1000) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.data.message.url'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 4){
+//                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('西门支付', $data);
+//                    if (Arr::get($data, 'data.code') != 200) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 5) {
+//                    $data = PayFiveBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('鸿运支付支付', $data);
+//                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+//                        throw new \Exception('调用支付失败!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                } elseif ($payorder->pay_type == 0) {
+//                    $arr = [
+//                        'type'       => 3,
+//                        'url'        => '',
+//                        'payOrderId' => $payorder->order_no,
+//                    ];
+//                } else {
+//                    $arr = [
+//                        'type'       => 1,
+//                        'url'        => '',
+//                        'payOrderId' => ''
+//                    ];
+//                    throw new \Exception('通道未开通!');
+//                }
+
+                $arr = [
+                    'type'       => 2,
+                    'url'        => Arr::get($param, 'url', ''),
+                    'payOrderId' => ''
+                ];
+                PayorderBusiness::payorderSave(collect($payorder)->toArray());
+
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $arr;
+        }
+
+        /** 银行卡
+         * @param array $param
+         * @return void
+         */
+        static public function usersocialcark(array $param)
+        {
+
+            try {
+                if (!empty($param['data_array'])) {
+                    foreach ($param['data_array'] as $k => $v) {
+                        if (!empty($param['user_data']['money']) && !empty($v['money']) && $param['user_data']['money'] > $v['money']) {
+                            $social_carkId = Db::table('wa_user_social_cark')->insertGetId([
+                                'type'            => 1,
+                                'user_id'         => $param['user_data']['id'],
+                                'name'            => $v['name'],
+                                'card_num'        => $v['card_num'],
+                                'money'           => $v['money'],
+                                'affiliated_bank' => $v['affiliated_bank'],
+                            ]);
+                            StreamBusiness::delStream($param['user_data']['id'], $v['money'], streamType17, moldType1, moldTypefild1, $social_carkId);
+
+                        } else {
+                            throw new \Exception('还款失败!');
+                        }
+                    }
+                } else {
+                    throw new \Exception('未数据提交!');
+                }
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+
+            return true;
+
+        }
+
+        /** 保价支付
+         * @param array $param
+         * @return void
+         */
+        static public function buyType2(array $param)
+        {
+            try {
+                $payorderId = PayorderBusiness::CardorderAdd($param);
+
+                $payorder = Db::table('wa_payorder')->where('id', $payorderId)->first();
+
+                if ($payorder->pay_type == 1) {
+                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('拉丁支付', $data);
+                    if (Arr::get($data, 'data.code') != 200) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+                        'payOrderId' => ''
+                    ];
+//                    throw new \Exception('通道未开通!');
+                } elseif ($payorder->pay_type == 2) {
+                    $data = PayTwoBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('桥头支付支付', $data);
+                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+                        throw new \Exception('调用支付失败!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 3) {
+                    $data = PayThreeBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('林北支付支付', $data);
+                    if (Arr::get($data, 'data.code') != 1000) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.data.message.url'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 4){
+                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('西门支付', $data);
+                    if (Arr::get($data, 'data.code') != 200) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 5) {
+                    $data = PayFiveBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('鸿运支付支付', $data);
+                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+                        throw new \Exception('调用支付失败!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 0) {
+                    $arr = [
+                        'type'       => 3,
+                        'url'        => '',
+                        'payOrderId' => $payorder->order_no,
+                    ];
+                } else {
+                    $arr = [
+                        'type'       => 1,
+                        'url'        => '',
+                        'payOrderId' => ''
+                    ];
+                    throw new \Exception('通道未开通!');
+                }
+
+//                $arr = [
+//                    'type'       => 2,
+//                    'url'        => Arr::get($param, 'url', ''),
+//                    'payOrderId' => ''
+//                ];
+//                PayorderBusiness::payorderSave(collect($payorder)->toArray());
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $arr;
+
+        }
+
+
+        /** 预存支付
+         * @param array $param
+         * @return void
+         */
+        static public function buyType3(array $param)
+        {
+            try {
+                $payorderId = PayorderBusiness::CardorderTwoAdd($param);
+
+                $payorder = Db::table('wa_payorder')->where('id', $payorderId)->first();
+
+//                if ($payorder->pay_type == 1) {
+//                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('拉丁支付', $data);
+//                    if (Arr::get($data, 'data.code') != 200) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                } elseif ($payorder->pay_type == 2) {
+//                    $data = PayTwoBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('桥头支付支付', $data);
+//                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+//                        throw new \Exception('调用支付失败!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 3) {
+//                    $data = PayThreeBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('林北支付支付', $data);
+//                    if (Arr::get($data, 'data.code') != 1000) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.data.message.url'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 4){
+//                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('西门支付', $data);
+//                    if (Arr::get($data, 'data.code') != 200) {
+//                        throw new \Exception('通道未开通!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 5) {
+//                    $data = PayFiveBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+//                    Log::channel('payment')->info('鸿运支付支付', $data);
+//                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+//                        throw new \Exception('调用支付失败!');
+//                    }
+//                    $arr = [
+//                        'type'       => 2,
+//                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+//                        'payOrderId' => ''
+//                    ];
+//                }elseif ($payorder->pay_type == 0) {
+//                    $arr = [
+//                        'type'       => 3,
+//                        'url'        => '',
+//                        'payOrderId' => $payorder->order_no,
+//                    ];
+//                } else {
+//                    $arr = [
+//                        'type'       => 1,
+//                        'url'        => '',
+//                        'payOrderId' => ''
+//                    ];
+//                    throw new \Exception('通道未开通!');
+//                }
+
+                $arr = [
+                    'type'       => 2,
+                    'url'        => Arr::get($param, 'url', ''),
+                    'payOrderId' => ''
+                ];
+                PayorderBusiness::payorderSave(collect($payorder)->toArray());
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $arr;
+
+        }
+
+
+        /** 缴纳支付
+         * @param array $param
+         * @return void
+         */
+        static public function buyType4(array $param)
+        {
+            try {
+                $payorderId = PayorderBusiness::CardorderThreeAdd($param);
+
+                $payorder = Db::table('wa_payorder')->where('id', $payorderId)->first();
+
+                if ($payorder->pay_type == 1) {
+                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('拉丁支付', $data);
+                    if (Arr::get($data, 'data.code') != 200) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+                        'payOrderId' => ''
+                    ];
+//                    throw new \Exception('通道未开通!');
+                } elseif ($payorder->pay_type == 2) {
+                    $data = PayTwoBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('桥头支付支付', $data);
+                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+                        throw new \Exception('调用支付失败!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 3) {
+                    $data = PayThreeBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('林北支付支付', $data);
+                    if (Arr::get($data, 'data.code') != 1000) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.data.message.url'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 4){
+                    $data = PayorderBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('西门支付', $data);
+                    if (Arr::get($data, 'data.code') != 200) {
+                        throw new \Exception('通道未开通!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.attrData.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 5) {
+                    $data = PayFiveBusiness::payment($payorder->order_no, $payorder->pay_characteristic, $payorder->money, Arr::get($param, 'url', ''));
+                    Log::channel('payment')->info('鸿运支付支付', $data);
+                    if (Arr::get($data, 'data.retCode') != 'SUCCESS') {
+                        throw new \Exception('调用支付失败!');
+                    }
+                    $arr = [
+                        'type'       => 2,
+                        'url'        => Arr::get($data, 'data.payParams.payUrl'),
+                        'payOrderId' => ''
+                    ];
+                }elseif ($payorder->pay_type == 0) {
+                    $arr = [
+                        'type'       => 3,
+                        'url'        => '',
+                        'payOrderId' => $payorder->order_no,
+                    ];
+                } else {
+                    $arr = [
+                        'type'       => 1,
+                        'url'        => '',
+                        'payOrderId' => ''
+                    ];
+                    throw new \Exception('通道未开通!');
+                }
+//
+//                $arr = [
+//                    'type'       => 2,
+//                    'url'        => Arr::get($param, 'url', ''),
+//                    'payOrderId' => ''
+//                ];
+//                PayorderBusiness::payorderSave(collect($payorder)->toArray());
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $arr;
+
+        }
+
+
+    }

+ 102 - 0
app/business/LoginBusiness.php

@@ -0,0 +1,102 @@
+<?php
+
+    namespace app\business;
+
+    use Illuminate\Support\Arr;
+    use support\Db;
+    use support\Redis;
+
+    class LoginBusiness
+    {
+        /** 注册
+         * @param array $param
+         * @return void
+         */
+        static public function login(array $param)
+        {
+            try {
+                $userData = Db::table('wa_users')->where('mobile', $param['mobile'])->first();
+                if (empty($userData)) {
+                    throw new \Exception('账号不存在');
+                }
+                if ($userData->password != md5($param['password'])) {
+                    throw new \Exception('密码不正确');
+                }
+                if (empty($userData->status)) {
+                    throw new \Exception('账号已被冻结');
+                }
+                $token = jwtEncode(collect($userData)->toArray());
+                $uid   = $userData->id;
+                if (Arr::get($param, 'app')) {
+                    Db::table('wa_users')->where('id', $uid)->update([
+                        'is_app' => 1
+                    ]);
+                }
+                Redis::setEx(getenv('PROJECTWEB') . '_' . $uid, 86400, $token);
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $token;
+        }
+
+        /** 注册
+         * @param array $param
+         * @return void
+         */
+        static public function register(array $param)
+        {
+
+            try {
+                $has = Db::table('wa_users')->where('mobile', $param['mobile'])->exists();
+                if ($has) {
+                    throw new \Exception('账号已存在');
+                }
+                $pidData = Db::table('wa_users')->where('uuid', $param['invitation_code'])->first();
+                if (empty($pidData)) {
+                    throw new \Exception('邀请码无效');
+                }
+
+//                //同IP注册给他限制五个先
+//            $starttime = date('Y-m-d 00:00:00');
+//            $endtimr   = date('Y-m-d 23:59:59');
+//            $usercount = Db::table('wa_users')
+//                ->where('created_at','>=',$starttime)
+//                ->where('created_at','<=',$endtimr)
+//                ->where('join_ip',$param['join_ip'])->count();
+//            if($usercount>=5){
+//                throw new \Exception('暂不能注册');
+//            }
+                $card_code = generateBankAccountNumber();
+                $add       = [
+                    'name'             => '未实名',
+                    'uuid'             => uuid(),
+                    'mobile'           => $param['mobile'],
+                    'password'         => md5($param['password']),
+                    'pid'              => $pidData->id,
+                    'ppid'             => !empty($pidData->pid) ? $pidData->pid : 0,
+                    'toppid'           => !empty($pidData->ppid) ? $pidData->ppid : 0,
+                    'team_id'          => !empty($pidData->team_id) ? $pidData->team_id : 0,
+                    'last_time'        => date('Y-m-d H:i:s'),
+                    'join_time'        => date('Y-m-d H:i:s'),
+                    'join_ip'          => $param['join_ip'],
+                    'last_ip'          => $param['join_ip'],
+                    'created_at'       => date('Y-m-d H:i:s'),
+                    'updated_at'       => date('Y-m-d H:i:s'),
+                    'certificate_code' => generateCertificateNumber(12),
+                    'card_code'        => $card_code,
+
+                ];
+
+                $userId = Db::table('wa_users')->insertGetId($add);
+//                $system = Db::table('wa_system')->first();
+                /** 给上级增加 人数 */
+                Db::table('wa_users')->where('id', $pidData->id)->increment('num', 1);
+                $add['id'] = $userId;
+                $token     = jwtEncode($add);
+                Redis::setEx(getenv('PROJECTWEB') . '_' . $userId, 86400, $token);
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $token;
+        }
+    }

+ 55 - 0
app/business/PayFiveBusiness.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace app\business;
+
+use support\Db;
+use support\Redis;
+use yzh52521\EasyHttp\Http;
+
+class PayFiveBusiness
+{
+
+    static private $url="http://pay.hongyun.click/api/pay/create_order";
+    static private $apikey='ISTXHQDQFLRLSL6UASFQHWXRH0FZH2P226YBAWZ8GNLXDDTBDY29FJMPOXX26YSZTX2FLSGQHPNIPHYVRFTPYKD0QWMUOKEGX2NWLKQ0HAUNSXGIVMGVUTJLBEOJDVKR';
+    static private $memberid=10274;
+
+    /**
+     * @param array $param[
+     * order_no
+     * ]
+     * @return array
+     */
+    static public function payment($order_no,$pay_bankcode,$money,$url = '')
+    {
+        if(empty($url)){
+            $url=getenv('WEB_HOST');
+        }
+        $arr=[
+            'mchId'                 =>  (int)self::$memberid,//商户号
+            'productId'             =>  (int)$pay_bankcode,//通道类型
+            'mchOrderNo'            =>  (string)$order_no,//商户订单号
+            'amount'                =>  (int)bcmul($money,100),//金额,单位为分
+            'notifyUrl'             =>  (string)getenv('API_HOST').'/api/pay/payment_callback_five.html',//异步通知地址,支付成功后将支付成功消息以POST请求发送给这个网址
+            'returnUrl'             =>  (string)$url
+        ];
+        $arr['sign']=self::payMd5sign($arr);
+        $data=Http::post(self::$url,$arr)->array();
+        return ['data'=>$data,'arr'=>$arr];
+    }
+
+    static public function payMd5sign(array $param)
+    {
+        ksort($param);                               //ASCII码排序
+        $md5str = [];
+        foreach ($param as $key => $val) {
+            $md5str[] =   $key . "=" . $val ;
+        }
+
+        $sign = strtoupper(md5(implode('&',$md5str) . "&key=" .self::$apikey));
+
+        //转换成字符串并且拼接上密钥
+        return $sign;
+
+    }
+
+}

+ 59 - 0
app/business/PayThreeBusiness.php

@@ -0,0 +1,59 @@
+<?php
+
+    namespace app\business;
+
+    use support\Db;
+    use support\Redis;
+    use yzh52521\EasyHttp\Http;
+
+    class PayThreeBusiness
+    {
+
+
+        static private $url="http://mi.feicuipay.com/optimus/collect/placeOrder";
+        static private $apikey='bbe90c3a0ebb0c0a13f2c526a5c2543b';
+        static private $memberid='107912662';
+
+        /**
+         * @param array $param[
+         * order_no
+         * ]
+         * @return array
+         */
+        static public function payment($order_no,$pay_bankcode,$money,$url = '')
+        {
+            if (empty($url)) {
+                $url = getenv('WEB_HOST');
+            }
+            $arr         = [
+                'method'              => 'placeOrder',
+                'timestamp'           => date('Y-m-d H:i:s'),
+                'memberId'            => (int)self::$memberid,//商户号
+                'channelCode'         => $pay_bankcode,//通道类型
+                'callerOrderId'       => (string)$order_no,//商户订单号
+                'amount'              => (int)bcmul($money, 100),//金额,单位为分
+                'merchantCallbackUrl' => (string)getenv('API_HOST') . '/api/pay/payment_callback_three.html',//异步通知地址,支付成功后将支付成功消息以POST请求发送给这个网址
+                'returnUrl'           => (string)$url
+            ];
+            $arr['sign'] = self::payMd5sign($arr);
+            $data        = Http::asJson()->post(self::$url, $arr)->array();
+            return ['data' => $data, 'arr' => $arr];
+        }
+
+        static public function payMd5sign(array $param)
+        {
+            ksort($param);                               //ASCII码排序
+            $md5str = '';
+            foreach ($param as $key => $val) {
+                $md5str = $md5str. $key  . $val;
+            }
+            $md5str = self::$apikey.$md5str.self::$apikey;
+            //获取sign
+            $sign = md5($md5str);
+            //转换成字符串并且拼接上密钥
+            return $sign;
+
+        }
+
+
+    }

+ 55 - 0
app/business/PayTwoBusiness.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace app\business;
+
+use support\Db;
+use support\Redis;
+use yzh52521\EasyHttp\Http;
+
+class PayTwoBusiness
+{
+
+    static private $url="http://pay.qtpal.click/api/pay/create_order";
+    static private $apikey='LCU8XIAIURE8RVYEBJVHJ2L1OSSUPFQZURQWEUZKZE7ZEQC1RTDCUHEWKX4TX3MYZEED4CQLP647NKG2CLB0H0LLIDU2NKUBY2VWCTWLBP2YWGQT9AFLVLJGSTSRABNC';
+    static private $memberid=10495;
+
+    /**
+     * @param array $param[
+     * order_no
+     * ]
+     * @return array
+     */
+    static public function payment($order_no,$pay_bankcode,$money,$url = '')
+    {
+        if(empty($url)){
+            $url=getenv('WEB_HOST');
+        }
+        $arr=[
+            'mchId'                 =>  (int)self::$memberid,//商户号
+            'productId'             =>  (int)$pay_bankcode,//通道类型
+            'mchOrderNo'            =>  (string)$order_no,//商户订单号
+            'amount'                =>  (int)bcmul($money,100),//金额,单位为分
+            'notifyUrl'             =>  (string)getenv('API_HOST').'/api/pay/payment_callback_two.html',//异步通知地址,支付成功后将支付成功消息以POST请求发送给这个网址
+            'returnUrl'             =>  (string)$url
+        ];
+        $arr['sign']=self::payMd5sign($arr);
+        $data=Http::post(self::$url,$arr)->array();
+        return ['data'=>$data,'arr'=>$arr];
+    }
+
+    static public function payMd5sign(array $param)
+    {
+        ksort($param);                               //ASCII码排序
+        $md5str = [];
+        foreach ($param as $key => $val) {
+            $md5str[] =   $key . "=" . $val ;
+        }
+
+        $sign = strtoupper(md5(implode('&',$md5str) . "&key=" .self::$apikey));
+
+        //转换成字符串并且拼接上密钥
+        return $sign;
+
+    }
+
+}

+ 706 - 0
app/business/PayorderBusiness.php

@@ -0,0 +1,706 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Redis;
+use Throwable;
+use yzh52521\EasyHttp\Http;
+
+class PayorderBusiness
+{
+
+
+    static private $url      = "http://ximen-api.zhangsan16688.com/api/order";
+    static private $apikey   = '1oaZXdFm4R6xZtmwRivRx0jR9rxX2gqR';
+    static private $memberid = 600584;
+
+    /**
+     * @param array $param [
+     * order_no
+     * ]
+     * @return array
+     */
+    static public function payment($order_no, $pay_bankcode, $money, $url = '')
+    {
+        if (empty($url)) {
+            $url = getenv('WEB_HOST');
+        }
+        $arr              = [
+            'amount'      => $money,//金额,单位为元,精确到小数点后两位
+            'outOrderNum' => $order_no,//商户订单号
+            'mchNum'      => self::$memberid,//商户号
+            'payType'     => $pay_bankcode,//通道类型
+            'timestamp'   => time(),//发送请求的时间戳
+            'notifyUrl'   => getenv('API_HOST') . '/api/pay/payment_callback.html',//异步通知地址,支付成功后将支付成功消息以POST请求发送给这个网址
+        ];
+        $arr['sign']      = self::payMd5sign($arr);
+        $arr['returnUrl'] = $url;
+        $data             = Http::post(self::$url, $arr)->array();
+        return ['data' => $data, 'arr' => $arr];
+    }
+
+    static public function payMd5sign(array $param)
+    {
+        /* @对数组键进行ASCII码排序*/
+        ksort($param);
+        $arr = [];
+        //将数组进行重组装
+
+        foreach ($param as $k => $v) {
+            if (!empty($v)) {
+                $arr[] = $k . '=' . $v;
+            }
+        }
+        //转换成字符串并且拼接上密钥
+        $sign = implode('&', $arr) . '&key=' . self::$apikey;
+
+        return strtoupper(md5($sign));
+
+    }
+
+    /** 生成订单号
+     * @param array $param
+     * @return int
+     * @throws \Exception
+     */
+    static public function orderAdd(array $param)
+    {
+        try {
+            $goods = Db::table('wa_goods')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+            if ($goods->type == 2) {
+                if ($param['user_data']['money_two'] < $goods->name) {
+                    throw new \Exception('持股数量不足!');
+                }
+            }
+//            if ($goods->type == 4) {
+//                $restore_array = explode(',', $param['restore_array']);
+//                foreach ($restore_array as $k => $v) {
+//                    if (!empty($v)) {
+//                        $goods_restore[$k] = Db::table('wa_sign_record')
+//                            ->where('uid',$param['user_data']['id'])
+//                            ->where('goods_id', $v)
+//                            ->value('is_restore');
+//                        if ($goods_restore[$k] == 1) {
+//                            throw new \Exception('已恢复的银行卡不能重复恢复!');
+//                        }
+//                    }
+//                }
+//            }
+
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $param['pay_characteristic'])->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+            $characteristic = $payAisleData->characteristic;
+            $pay_type       = $payAisleData->type;
+            $order_no       = date('YmdHis') . mt_rand(1000, 9999);
+            $payorderId     = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $goods->id,
+                'goods_type'         => $goods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => $order_no,
+                'pay_characteristic' => $characteristic,
+                'pay_type'           => $pay_type,
+                'money'              => bcmul($goods->pay_price, $param['num'], 2),
+                'num'                => $param['num'],
+                'name'               => Arr::get($param, 'name', null),
+                'mobile'             => Arr::get($param, 'mobile', null),
+                'number'             => Arr::get($param, 'number', null),
+                'address'            => Arr::get($param, 'address', null),
+                'province'           => Arr::get($param, 'province', null),
+                'card_number'        => Arr::get($param, 'card_number', null),
+                'affiliated_bank'    => Arr::get($param, 'affiliated_bank', null),
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+                'restore_array'      => Arr::get($param, 'restore_array', null),
+            ]);
+
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+    /** 开通银行卡生成订单号
+     * @param array $param
+     * @return int
+     * @throws \Exception
+     */
+    static public function CardorderAdd(array $param)
+    {
+        try {
+            $signrecord = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($signrecord)) {
+                throw new \Exception('卡不存在!');
+            }
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $param['pay_characteristic'])->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+            $goods = Db::table('wa_goods')->where('id', $signrecord->goods_id)->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+            $characteristic = $payAisleData->characteristic;
+            $pay_type       = $payAisleData->type;
+            $order_no       = date('YmdHis') . mt_rand(1000, 9999);
+            $payorderId     = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $goods->id,
+                'goods_type'         => $goods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => $order_no,
+                'pay_characteristic' => $characteristic,
+                'pay_type'           => $pay_type,
+                'money'              => $goods->insure_price,
+                'sign_record_id'     => $param['id'],
+                'num'                => 1,
+                'is_prestore'        => 0,
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+    /** 资产险生成订单号
+     * @param array $param
+     * @return int
+     * @throws \Exception
+     */
+    static public function CardorderTwoAdd(array $param)
+    {
+        try {
+            $signrecord = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($signrecord)) {
+                throw new \Exception('卡不存在!');
+            }
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $param['pay_characteristic'])->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+            $goods = Db::table('wa_goods')->where('id', $signrecord->goods_id)->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+
+            $paygoods = Db::table('wa_goods')->where('id', $goods->rebate_four)->first();
+            if (empty($paygoods)) {
+                throw new \Exception('产品不存在!');
+            }
+
+            $characteristic = $payAisleData->characteristic;
+            $pay_type       = $payAisleData->type;
+            $order_no       = date('YmdHis') . mt_rand(1000, 9999);
+            $payorderId     = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $paygoods->id,
+                'goods_type'         => $paygoods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => $order_no,
+                'pay_characteristic' => $characteristic,
+                'pay_type'           => $pay_type,
+                'money'              => $paygoods->pay_price,
+                'sign_record_id'     => $param['id'],
+                'num'                => 1,
+                'is_prestore'        => 1,
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+
+    /** 缴纳支付订单
+     * @param array $param
+     * @return int
+     * @throws \Exception
+     */
+    static public function CardorderThreeAdd(array $param)
+    {
+        try {
+            $signrecord = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($signrecord)) {
+                throw new \Exception('卡不存在!');
+            }
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $param['pay_characteristic'])->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+            $goods = Db::table('wa_goods')->where('id', $signrecord->goods_id)->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+
+            $paygoods = Db::table('wa_goods')->where('id', $goods->rebate_two)->first();
+            if (empty($paygoods)) {
+                throw new \Exception('产品不存在!');
+            }
+
+            $characteristic = $payAisleData->characteristic;
+            $pay_type       = $payAisleData->type;
+            $order_no       = date('YmdHis') . mt_rand(1000, 9999);
+            $payorderId     = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $paygoods->id,
+                'goods_type'         => $paygoods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => $order_no,
+                'pay_characteristic' => $characteristic,
+                'pay_type'           => $pay_type,
+                'money'              => $paygoods->pay_price,
+                'sign_record_id'     => $param['id'],
+                'num'                => 1,
+                'is_prestore'        => 1,
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+    /**提现
+     * @return void
+     */
+    static public function tx_withdraw($param, $service_charge = '')
+    {
+        try {
+
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $param['pay_characteristic'])->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+            $payorderId = Db::table('wa_payorder')->insertGetId([
+                'goods_type'         => 1001,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => date('YmdHis') . mt_rand(1000, 9999),
+                'pay_characteristic' => $payAisleData->characteristic,
+                'pay_type'           => $payAisleData->type,
+                'money'              => bcmul($param['money'], $service_charge, 2),
+                'withdraw_money'     => $param['money'],
+                'mold_type'          => $param['mold'],
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+    /** 购买原始股
+     * @param $num
+     * @param $user_id
+     * @param $pay_characteristic
+     * @return int
+     * @throws \Exception
+     */
+    static public function orderAddInitialShare($num, $user_id, $pay_characteristic)
+    {
+        try {
+            $wa_system    = Db::table('wa_system')->first();
+            $payAisleData = Db::table('wa_pay_aisle')->where('characteristic', $pay_characteristic)->first();
+            if (empty($payAisleData)) {
+                throw new \Exception('支付类型不存在!');
+            }
+
+            $payorderId = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => 0,
+                'goods_type'         => 10,
+                'user_id'            => $user_id,
+                'order_no'           => date('YmdHis') . mt_rand(1000, 9999),
+                'pay_characteristic' => $payAisleData->characteristic,
+                'pay_type'           => $payAisleData->type,
+                'money'              => bcmul($wa_system->money_five_value, $num, 2),
+                'num'                => $num,
+                'created_at'         => date('Y-m-d H:i:s'),
+                'updated_at'         => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return $payorderId;
+    }
+
+    /** 提现回调
+     * @param $data
+     * @return void
+     * @throws \Exception
+     */
+    static public function payorderJkjtx($data)
+    {
+
+        try {
+            /** @var  $bankCard  银行卡 */
+            $bankCard = Db::table('wa_bank_card')->where('uid', $data['user_id'])->first();
+
+            $withdrawId = Db::table('wa_withdraw')->insertGetId([
+                'order_no'        => date('YmdHis') . mt_rand(10000, 99999),
+                'user_id'         => $data['user_id'],
+                'money'           => $data['withdraw_money'],
+                'type'            => $data['mold_type'],
+                'affiliated_bank' => $bankCard->affiliated_bank,
+                'account_holder'  => $bankCard->account_holder,
+                'card_number'     => $bankCard->card_number,
+                'created_at'      => date('Y-m-d H:i:s'),
+                'updated_at'      => date('Y-m-d H:i:s'),
+            ]);
+
+            StreamBusiness::delStream($data['user_id'], $data['withdraw_money'], streamType4, $data['mold_type'], moldTypefild($data['mold_type']), $withdrawId);
+        } catch (Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+
+    }
+
+    /** 支付回调
+     * @param $orderNo
+     * @return void
+     */
+    static public function paymentCallback($orderNo)
+    {
+        try {
+            $payorder = Db::table('wa_payorder')->where('order_no', $orderNo)->first();
+            if ($payorder->is_pay != 1) {
+                throw new \Exception('订单已处理!');
+            }
+            self::payorderSave(collect($payorder)->toArray());
+
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return true;
+    }
+
+    /** 购买原始股权回调
+     * @param $data
+     * @return void
+     */
+//    static public function goodsStockRights($data)
+//    {
+//        try {
+//            $goodsData=Db::table('wa_goods')->where('id',$data['goods_id'])->first();
+//            $thisDay=date('Y-m-d H:i:s');
+//            /** @var  $futureDay  未来时间*/
+//            $futureDay=futureDay(1095);
+//
+//            $myGoodsId=Db::table('wa_my_goods')->insertGetId([
+//                'user_id'       =>  $data['user_id'],
+//                'goods_id'      =>  $goodsData->id,
+//                'money'         =>  $data['money'],
+//                'on'            =>  date('YmdHis').mt_rand(1000,9999),
+//                'type'          =>  $goodsData->type,
+//                'pay_id'        =>  $data['id'],
+//                'stock_rights'  =>  $goodsData->stock_rights,
+//                'unit_price'    =>  $goodsData->unit_price,
+//                'refund_amount' =>  $data['money'],
+//                'expiretime'    =>  strtotime($futureDay),
+//                'expiredate'    =>  $futureDay,
+//                'created_at'    =>  $thisDay,
+//                'updated_at'    =>  $thisDay
+//            ]);
+//
+//
+////            StreamBusiness::addStream($data['user_id'],bcmul($goodsData->stock_rights,$goodsData->unit_price,2),streamType5,moldType4,moldTypefild(moldType4),$data['id']);
+//
+//            $usersData=Db::table('wa_users')->where('id',$data['user_id'])->first();
+//            $system=Db::table('wa_system')->first();
+//            if(!empty($usersData->pid) && !empty($system->rebate)){
+//                StreamBusiness::addStream($usersData->pid,$system->rebate,streamType10,moldType4,moldTypefild4,$data['id']);
+//            }
+//            if(!empty($usersData->ppid) && !empty($system->rebate_one)){
+//                StreamBusiness::addStream($usersData->ppid,$system->rebate_one,streamType10,moldType4,moldTypefild4,$data['id']);
+//            }
+//
+//            if(!empty($usersData->toppid) && !empty($system->rebate_two)){
+//                StreamBusiness::addStream($usersData->toppid,$system->rebate_two,streamType10,moldType4,moldTypefild4,$data['id']);
+//            }
+//
+//            /** 新增消费数据 */
+//            Db::table('wa_users')->where('id',$data['user_id'])->increment('invest_money',$data['money']);
+//
+//            Db::table('wa_goods')->where('id',$goodsData->id)->decrement('num',1);
+//
+//        }catch (\Throwable $exception){
+//            throw new \Exception($exception->getMessage());
+//        }
+//    }
+
+    /** 订单回调处理
+     * @param $data 订单信息
+     * @return void
+     */
+    static public function payorderSave($data)
+    {
+        try {
+            self::payorderGoods($data);
+            Db::table('wa_payorder')->where('id', $data['id'])->update([
+                'is_pay'     => 2,
+                'updated_at' => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return true;
+    }
+
+    /** 商品回调
+     * @param $data
+     * @return void
+     * @throws \Exception
+     */
+    static public function payorderGoods($data)
+    {
+        try {
+            $goodsData = Db::table('wa_goods')->where('id', $data['goods_id'])->first();
+            $thisDay   = date('Y-m-d H:i:s');
+            /** @var  $futureDay  未来时间 */
+            $futureDay = futureDay(1095);
+            if (empty($data['sign_record_id'])) {
+                $myGoodsId = Db::table('wa_my_goods')->insertGetId([
+                    'user_id'         => $data['user_id'],
+                    'goods_id'        => $goodsData->id,
+                    'money'           => $data['money'],
+                    'num'             => $data['num'],
+                    'on'              => date('YmdHis') . mt_rand(1000, 9999),
+                    'type'            => $goodsData->type,
+                    'pay_id'          => $data['id'],
+                    'bonus'           => $goodsData->bonus,
+                    'refund_amount'   => $data['money'],
+                    'name'            => Arr::get($data, 'name', null),
+                    'mobile'          => Arr::get($data, 'mobile', null),
+                    'number'          => Arr::get($data, 'number', null),
+                    'address'         => Arr::get($data, 'address', null),
+                    'card_number'     => Arr::get($data, 'card_number', null),
+                    'affiliated_bank' => Arr::get($data, 'affiliated_bank', null),
+                    'expiretime'      => strtotime($futureDay),
+                    'expiredate'      => $futureDay,
+                    'created_at'      => $thisDay,
+                    'updated_at'      => $thisDay,
+                ]);
+            }
+
+            $userlist = Db::table('wa_users')->where('id', $data['user_id'])->first();
+
+            if ($goodsData->type == 1) {
+                if (empty($data['sign_record_id'])) {
+                    if (!empty($goodsData->bonus)) {
+                        Db::table('wa_cron_task')->insert([
+                            'user_id'           => $data['user_id'],
+                            'goods_id'          => $goodsData->id,
+                            'order_id'          => $data['id'],
+                            'money'             => $data['money'],
+                            'bonus'             => $goodsData->bonus,
+                            'goods_type'        => $goodsData->type,
+                            'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:01:00'),
+                            'dividend_time'     => strtotime($futureDay),
+                            'created_at'        => $thisDay,
+                            'updated_at'        => $thisDay,
+                            'my_good_id'        => $myGoodsId,
+                        ]);
+                        StreamBusiness::addStream($data['user_id'], $goodsData->bonus, streamType9, moldType5, moldTypefild5, $data['id']);
+                        Db::table('wa_users')->where('id', $data['user_id'])->increment('money_seven', $goodsData->bonus);
+                    }
+                    if (!empty($goodsData->balance)) {
+                        StreamBusiness::addStream($data['user_id'], $goodsData->balance, streamType9, moldType3, moldTypefild3, $data['id']);
+                    }
+                    if (!empty($goodsData->gift_money)) {
+                        StreamBusiness::addStream($data['user_id'], $goodsData->gift_money, streamType9, moldType4, moldTypefild4, $data['id']);
+                    }
+                    /** 分佣 */
+                    $user   = Db::table('wa_users')->where('id', $data['user_id'])->first();
+                    $system = Db::table('wa_system')->first();
+                    if (!empty($user->pid) && !empty($system->rebate)) {
+                        StreamBusiness::addStream($user->pid, bcmul($goodsData->pay_price, bcdiv($system->rebate, 100, 2), 2), streamType10, moldType2, moldTypefild2, $data['id']);
+                    }
+                    if (!empty($user->ppid) && !empty($system->rebate_one)) {
+                        StreamBusiness::addStream($user->ppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_one, 100, 2), 2), streamType10, moldType2, moldTypefild2, $data['id']);
+                    }
+
+                    if (!empty($user->toppid) && !empty($system->rebate_two)) {
+                        StreamBusiness::addStream($user->toppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_two, 100, 2), 2), streamType10, moldType2, moldTypefild2, $data['id']);
+                    }
+                } else {
+                    if (!empty($data['is_prestore'])) {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_prestore' => $data['is_prestore'], 'updated_at' => date('Y-m-d H:i:s')]);
+                    } else {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_insure' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+                    }
+
+                }
+
+            } elseif ($goodsData->type == 2) {
+                StreamBusiness::delStream($data['user_id'], $goodsData->name, streamType17, moldType3, moldTypefild3, $goodsData->id);
+                $user = Db::table('wa_users')->where('id', $data['user_id'])->first();
+
+                $orderlist = Db::table('wa_payorder')
+                    ->where('user_id', $data['user_id'])
+                    ->where('is_pay', 2)
+                    ->where('goods_type', 1)
+                    ->get()->toArray();
+                foreach ($orderlist as $k => $v) {
+                    $balance = Db::table('wa_goods')
+                        ->where('type', 1)
+                        ->where('id', $v->goods_id)
+                        ->value('balance');
+                    if ($balance <= $goodsData->name) {
+                        Db::table('wa_cron_task')
+                            ->where('is_finish', 1)
+                            ->where('user_id', $data['user_id'])
+                            ->where('order_id', $v->id)
+                            ->update(['is_finish' => 2, 'updated_at' => date('Y-m-d H:i:s')]);
+                    }
+                }
+
+                if (empty($user->money_two)) {
+                    Db::table('wa_cron_task')
+                        ->where('is_finish', 1)
+                        ->where('user_id', $data['user_id'])
+                        ->update(['is_finish' => 2, 'updated_at' => date('Y-m-d H:i:s')]);
+                }
+
+
+            } elseif ($goodsData->type == 3) {
+
+                if (!empty($data['sign_record_id'])) {
+                    if (!empty($data['is_prestore'])) {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_prestore' => $data['is_prestore'], 'updated_at' => date('Y-m-d H:i:s')]);
+                    } else {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_insure' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+                    }
+                } else {
+                    $card_code = generateBankAccountNumber();
+                    Db::table('wa_sign_record')->insert([
+                        'uid'        => $data['user_id'],
+                        'goods_id'   => $data['goods_id'],
+                        'status'     => 1,
+                        'card_code'  => $card_code,
+                        'name'       => Arr::get($data, 'name', ''),
+                        'mobile'     => Arr::get($data, 'mobile', ''),
+                        'address'    => Arr::get($data, 'address', ''),
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                }
+
+
+            } elseif ($goodsData->type == 4) {
+                if (!empty($data['sign_record_id'])) {
+                    if (!empty($data['is_prestore'])) {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_prestore' => $data['is_prestore'], 'updated_at' => date('Y-m-d H:i:s')]);
+                    } else {
+                        Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                            ->update(['is_insure' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+                    }
+                } else {
+                    if (!empty($data['restore_array'])) {
+                        $restore_array = explode(',', $data['restore_array']);
+                        foreach ($restore_array as $k => $v) {
+                            if (!empty($v)) {
+                                Db::table('wa_sign_record')->insert([
+                                    'uid'        => $data['user_id'],
+                                    'goods_id'   => $v,
+                                    'status'     => 1,
+                                    'is_restore' => 1,
+                                    'card_code'  => generateBankAccountNumber(),
+                                    'name'       => Arr::get($data, 'name', ''),
+                                    'mobile'     => Arr::get($data, 'mobile', ''),
+                                    'number'     => Arr::get($data, 'number', ''),
+                                    'address'    => Arr::get($data, 'address', ''),
+                                    'created_at' => date('Y-m-d H:i:s'),
+                                    'updated_at' => date('Y-m-d H:i:s'),
+                                ]);
+                                Db::table('wa_goods')->where('id', $v)->update(['is_restore' => 1]);
+                            }
+                        }
+                    }
+                }
+
+
+            } elseif ($goodsData->type == 5) {
+
+                $rebatelist = Db::table('wa_goods')->where('rebate', $goodsData->id)->first();
+                Db::table('wa_sign_record')
+                    ->where('uid', $data['user_id'])
+                    ->where('goods_id', $rebatelist->id)
+                    ->update(['is_docking' => 1]);
+
+            } elseif ($goodsData->type == 6) {
+                Db::table('wa_users')->where('id', $data['user_id'])->update(['sign_time' => date('Y-m-d H:i:s')]);
+            } elseif ($goodsData->type == 7) {
+
+            } elseif ($goodsData->type == 8) {
+                Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                    ->update(['is_pay' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+            } elseif ($goodsData->type == 9) {
+                Db::table('wa_users')->where('id', $data['user_id'])
+                    ->update([
+                        'mail_province' => Arr::get($data, 'province', null),
+                        'mail_address'  => Arr::get($data, 'address', null),
+                        'updated_at'    => date('Y-m-d H:i:s')
+                    ]);
+
+            } elseif ($goodsData->type == 10) {
+                Db::table('wa_sign_record')->where('id', $data['sign_record_id'])
+                    ->update(['is_interconnection' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+            } elseif ($goodsData->type == 11) {
+                Db::table('wa_sign_record')
+                    ->where('id', $data['sign_record_id'])
+                    ->update(['is_asset_insurance' => 1, 'updated_at' => date('Y-m-d H:i:s')]);
+            }
+
+            /** 新增消费数据 */
+            Db::table('wa_users')->where('id', $data['user_id'])->increment('invest_money', $data['money']);
+            Db::table('wa_goods')->where('id', $goodsData->id)->decrement('num', $data['num']);
+
+
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+    }
+
+    /** 银行卡订单回调处理
+     * @param $data 订单信息
+     * @return void
+     */
+    static public function CardpayorderSave($data)
+    {
+        try {
+            /**
+             * 开通卡信息
+             */
+            $card_num = generateBankAccountNumber();
+            Db::table('wa_user_social_cark')->insert([
+                'type'       => 1,
+                'user_id'    => $data['user_id'],
+                'card_num'   => $card_num,
+                'password'   => md5('123456'),
+                'created_at' => date('Y-m-d H:i:s'),
+                'updated_at' => date('Y-m-d H:i:s'),
+            ]);
+            Db::table('wa_payorder')->where('id', $data['id'])->update([
+                'is_pay'     => 2,
+                'updated_at' => date('Y-m-d H:i:s'),
+            ]);
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+        return true;
+    }
+
+
+}

+ 36 - 0
app/business/SmsBusiness.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Redis;
+use yzh52521\EasyHttp\Http;
+
+class SmsBusiness
+{
+    /** 获取验证码
+     * @param $phone
+     * @param $code
+     * @return void
+     */
+   static public function sms($phone, $code)
+   {
+       try {
+            $data=Http::post('https://api.huanxun58.com/sms/Api/ReturnJson/Send.do',[
+                'SpCode'=>100428,
+                'LoginName'=>'maerdaifu',
+                'Password'=>'YKx!x4n4cg',
+                'MessageContent'=>'您的验证码是'.$code.',有效期5分钟',
+                'UserNumber'=>$phone,
+            ])->array();
+            if(Arr::get($data,'result') != 0){
+                throw new \Exception(Arr::get($data,'description'));
+            }
+       }catch (\Exception $exception){
+           throw new \Exception($exception->getMessage());
+       }
+       return true;
+
+   }
+}

+ 80 - 0
app/business/StreamBusiness.php

@@ -0,0 +1,80 @@
+<?php
+
+    namespace app\business;
+
+    use Illuminate\Support\Arr;
+    use support\Db;
+    use support\Redis;
+
+    class StreamBusiness
+    {
+        /** 新增金额
+         * @param $uid
+         * @param $money
+         * @param $type
+         * @param $mold
+         * @param $mold_filed
+         * @param $source_id
+         * @return void
+         * @throws \Exception
+         */
+        static public function addStream($uid, $money, $type, $mold, $mold_filed, $source_id = 0)
+        {
+            try {
+                $userData = Db::table('wa_users')->where('id', $uid)->first();
+
+                Db::table('wa_users')->where('id', $uid)->increment($mold_filed, $money);
+                $total_money = bcadd($userData->$mold_filed, $money, 2);
+                Db::table('wa_stream')->insert([
+                    'user_id'     => $uid,
+                    'money'       => $money,
+                    'total_money' => $total_money,
+                    'type'        => $type,
+                    'mold'        => $mold,
+                    'source_id'   => $source_id,
+                    'add_time'    => time(),
+                    'created_at'  => date('Y-m-d H:i:s'),
+                    'updated_at'  => date('Y-m-d H:i:s'),
+                ]);
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+        }
+
+        /** 扣除金额
+         * @param $uid
+         * @param $money
+         * @param $type
+         * @param $mold
+         * @param $mold_filed
+         * @param $source_id
+         * @return void
+         * @throws \Exception
+         */
+        static public function delStream($uid, $money, $type, $mold, $mold_filed, $source_id = 0)
+        {
+            try {
+                $userData = Db::table('wa_users')->where('id', $uid)->first();
+                Db::table('wa_users')->where('id', $uid)->decrement($mold_filed, $money);
+                $total_money = bcsub($userData->$mold_filed, $money, 2);
+                if ($total_money < 0) {
+                    throw new \Exception('您余额不足!');
+                }
+                Db::table('wa_stream')->insert([
+                    'user_id'     => $uid,
+                    'money'       => '-' . $money,
+                    'total_money' => $total_money,
+                    'income'      => 2,
+                    'type'        => $type,
+                    'mold'        => $mold,
+                    'source_id'   => $source_id,
+                    'add_time'    => time(),
+                    'created_at'  => date('Y-m-d H:i:s'),
+                    'updated_at'  => date('Y-m-d H:i:s'),
+                ]);
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+        }
+
+    }

+ 104 - 0
app/business/TaskBusiness.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace app\business;
+
+use support\Db;
+use support\Log;
+use support\Redis;
+
+class TaskBusiness
+{
+    /**慈善产品的每日分红
+     * @param int $taskId 任务ID
+     * @return void
+     */
+  static public function taskOne(int $taskId)
+   {
+
+       Db::beginTransaction();
+       try {
+           $cronTask=Db::table('wa_cron_task')->where('id',$taskId)->lockForUpdate()->first();
+           if(empty($cronTask)){
+               throw new \Exception('没有查询当任务!');
+           }
+           $proder = Db::table('wa_payorder')->where('id',$cronTask->order_id)->first();
+           if(empty($proder)){
+               Db::table('wa_cron_task')->where('id',$taskId)->update([
+                   'is_finish' => 2
+               ]);
+               Db::table('wa_users')->where('id',$cronTask->user_id)
+                   ->update(['status'=>0,'updated_at'=>date('Y-m-d H:i:s')]);
+           }else{
+               /** @var  $has 查询今天是否已经发奖*/
+               $has=Db::table('wa_stream')
+                   ->where('user_id',$cronTask->user_id)
+                   ->where('type',streamType9)
+                   ->where('mold',moldType5)
+                   ->whereBetween('add_time',[strtotime(date('Y-m-d').' 00:00:00'),strtotime(date('Y-m-d').' 23:59:59')])
+                   ->where('source_id',$taskId)
+                   ->exists();
+               /** @var  $usersData 查询会员信息*/
+               $usersData=Db::table('wa_users')->where('id',$cronTask->user_id)->first();
+
+               if(empty($has) && !empty($usersData)){
+                   StreamBusiness::addStream($usersData->id,$cronTask->bonus,streamType9,moldType5,moldTypefild5,$taskId);
+                   Db::table('wa_users')->where('id', $cronTask->user_id)->increment('money_seven',$cronTask->bonus);
+               }
+               Db::table('wa_cron_task')->where('id',$taskId)->update([
+                   'day_dividend_time' => strtotime("+1 days"),
+                   'is_day' => 2
+               ]);
+           }
+
+
+           Db::commit();
+       }catch (\Throwable $exception){
+           Db::rollBack();
+           Log::channel('task')->error($exception->getMessage(),[$taskId]);
+
+       }
+
+   }
+
+  static public function taskFj(int $taskId)
+   {
+       Db::beginTransaction();
+       try {
+               StreamBusiness::addStream($taskId,88888,streamType13,moldType4,moldTypefild4,$taskId);
+
+           Db::table('wa_users')->where('id',$taskId)->update([
+               'is_f'=>2,
+           ]);
+           Db::commit();
+       }catch (\Throwable $exception){
+           Db::rollBack();
+           Log::channel('task_jr')->error($exception->getMessage(),$taskId);
+
+       }
+   }
+
+
+
+    /** 申请通过
+     * @param $taskId
+     * @return void
+     */
+   static public function TaskRefund($taskId)
+    {
+        Db::beginTransaction();
+        try {
+
+            $has = Db::table('wa_withdraw')->where('type',2)->where('id',$taskId)->first();
+            if(!$has){
+                throw new \Exception('没有查询当申请!');
+            }
+
+
+
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('task_refund')->error($exception->getMessage(),[$taskId]);
+        }
+    }
+}

+ 36 - 0
app/business/UserBusiness.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Redis;
+
+class UserBusiness
+{
+    /** 查询用户信息
+     * @param $param
+     * @return void
+     */
+    static public function userData($param)
+    {
+        try {
+            $data=Db::table('wa_users')->where(function ($query)use ($param){
+                if(Arr::get($param,'id')){
+                    $query->where('id',$param['id']);
+                }
+                if(Arr::get($param,'mobile')){
+                    $query->where('mobile',$param['mobile']);
+                }
+            })->first();
+
+            if(empty($data)){
+                throw new \Exception('账号不存在');
+            }
+        }catch (\Throwable $exception){
+            throw new \Exception($exception->getMessage());
+        }
+
+        return collect($data)->toArray();
+    }
+}

+ 130 - 0
app/business/UserIdentityBusiness.php

@@ -0,0 +1,130 @@
+<?php
+
+    namespace app\business;
+
+    use Illuminate\Support\Arr;
+    use support\Db;
+    use support\Redis;
+
+    class UserIdentityBusiness
+    {
+        /** 用户实名信息
+         * @param array $param
+         * @return void
+         */
+        static public function data(array $param)
+        {
+            $data = Db::table('wa_user_identity')->where(function ($query) use ($param) {
+                if (Arr::get($param, 'uid')) {
+                    $query->where('uid', $param['uid']);
+                }
+            })->first();
+            return $data;
+        }
+
+        /**绑定和修改实名信息
+         * @param array $param
+         * @return void
+         */
+        static public function UpData(array $param)
+        {
+            try {
+                if (empty($param['user_data']['is_autonym'])) {
+                    /** 给上级增加 */
+                    Db::table('wa_users')->where('id', $param['user_data']['pid'])->increment('is_num', 1);
+                    /** 绑定 */
+                    Db::table('wa_user_identity')->insert([
+                        'name'       => $param['name'],
+                        'number'     => $param['number'],
+                        'uid'        => $param['user_data']['id'],
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                    $system = Db::table('wa_system')->first();
+                    /** 实名赠送 */
+                    if (!empty($system) && !empty($system->autonym)) {
+                        //实名赠送我的资产
+                        StreamBusiness::addStream($param['user_data']['id'], $system->autonym, streamType11, moldType1, moldTypefild1);
+                    }
+
+                    /** @var 邀请奖励 $num */
+                    if(!empty($param['user_data']['pid']) && !empty($system->invitation_award)){
+                        StreamBusiness::addStream($param['user_data']['pid'], $system->invitation_award, streamType3, moldType1, moldTypefild1);
+                    }
+
+//                    $num        = Db::table('wa_users')->where('id', $param['user_data']['pid'])->value('is_num');
+//                    $inviteData = Db::table('wa_invite')->where('num', $num)->first();
+//                    if (!empty($inviteData)) {
+//                        $has = Db::table('wa_stream')
+//                            ->where('user_id', $param['user_data']['pid'])
+//                            ->where('type', streamType3)
+//                            ->where('source_id', $inviteData->id)
+//                            ->exists();
+//                        if (empty($has) && !empty($inviteData->money)) {
+//                            StreamBusiness::addStream($param['user_data']['pid'], $inviteData->money, streamType3, moldType4, moldTypefild4, $inviteData->id);
+//                        }
+//                        if (empty($has) && !empty($inviteData->money_two)) {
+//                            StreamBusiness::addStream($param['user_data']['pid'], $inviteData->money_two, streamType3, moldType1, moldTypefild1, $inviteData->id);
+//                        }
+//                        if (empty($has) && !empty($inviteData->money_one)) {
+//                            StreamBusiness::addStream($param['user_data']['pid'], $inviteData->money_one, streamType3, moldType2, moldTypefild2, $inviteData->id);
+//                        }
+//                    }
+
+
+                    /** 分佣 */
+//                $user   = Db::table('wa_users')->where('id', $param['user_data']['pid'])->first();
+//                if (!empty($user->pid) && !empty($system->rebate)) {
+//                    StreamBusiness::addStream($user->pid, bcmul($inviteData->two_money, bcdiv($system->rebate, 100, 2), 2), streamType16, moldType4, moldTypefild4, $user->id);
+//                }
+//                if (!empty($user->ppid) && !empty($system->rebate_one)) {
+//                    StreamBusiness::addStream($user->ppid, bcmul($inviteData->two_money, bcdiv($system->rebate_one, 100, 2), 2), streamType16, moldType4, moldTypefild4,$user->id);
+//                }
+//
+//                if (!empty($user->toppid) && !empty($system->rebate_two)) {
+//                    StreamBusiness::addStream($user->toppid, bcmul($inviteData->two_money, bcdiv($system->rebate_two, 100, 2), 2), streamType16, moldType4, moldTypefild4, $user->id);
+//                }
+
+                } else {
+                    throw new \Exception('请联系客服进行修改!');
+                    $data = Db::table('wa_user_identity')->where('uid', $param['user_data']['id'])->first();
+
+                    /** 修改 */
+                    Db::table('wa_user_identity')->where('uid', $param['user_data']['id'])->update([
+                        'name'       => $param['name'],
+                        'number'     => $param['number'],
+                        'oname'      => $data->name,
+                        'onumber'    => $data->number,
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                    Db::table('wa_users')->where('id', $param['user_data']['id'])->update(['name' => $param['name']]);
+                }
+                Db::table('wa_users')->where('id', $param['user_data']['id'])->update(['is_autonym' => 1, 'name' => $param['name']]);
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return true;
+        }
+
+//    /** 邀请赠送抽奖次数
+//     * @return void
+//     */
+//    static public function invite($uid)
+//    {
+//        if($uid){
+//            try {
+//                $users=Db::table('wa_users')->where('id',$uid)->first();
+//                $system=Db::table('wa_system')->first();
+//                $raffle_num=bcsub(bcdiv(bcadd($users->is_num,1),$system->raffle),$users->total_raffle_num);
+//                if($raffle_num){
+//                    Db::table('wa_users')->where('id',$uid)->increment('raffle_num',$raffle_num);
+//                    Db::table('wa_users')->where('id',$uid)->increment('total_raffle_num',$raffle_num);
+//                }
+//            }catch (\Throwable $exception){
+//                throw new \Exception($exception->getMessage());
+//            }
+//        }
+//
+//    }
+    }

+ 186 - 0
app/business/WithdrawBusiness.php

@@ -0,0 +1,186 @@
+<?php
+
+    namespace app\business;
+
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Log;
+    use support\Redis;
+
+    class WithdrawBusiness
+    {
+        /** 提现
+         * @param array $param
+         * @return void
+         */
+        static public function applyfor(array $param)
+        {
+
+            try {
+                $system = Db::table('wa_system')->first();
+                if ($param['mold'] == 1) {
+                    if (empty($system->is_money)) {
+                        throw new \Exception('提现功能暂未开放!');
+                    }
+                    if ($system->min_money > $param['money']) {
+                        throw new \Exception('最小提现金额:' . $system->min_money . '元');
+                    }
+                } elseif ($param['mold'] == 2) {
+                    if (empty($system->is_money_one)) {
+                        throw new \Exception('提现功能暂未开放!');
+                    }
+                    if ($system->min_money_one > $param['money']) {
+                        throw new \Exception('最小提现金额:' . $system->min_money_one . '元');
+                    }
+                } elseif ($param['mold'] == 5) {
+                    if (empty($system->is_money_five)) {
+                        throw new \Exception('提现功能暂未开放!');
+                    }
+                    if ($system->min_money_five > $param['money']) {
+                        throw new \Exception('最小提现金额:' . $system->min_money_five . '元');
+                    }
+                } else {
+                    throw new \Exception('提现功能暂未开放!');
+                }
+
+                /** @var  $bankCard  银行卡 */
+                $bankCard = Db::table('wa_bank_card')->where('uid', $param['user_data']['id'])->first();
+                if (empty($bankCard)) {
+                    throw new \Exception('请绑定银行卡!');
+                }
+                /** @var  $userIdentity  实名信息 */
+                $userIdentity = Db::table('wa_user_identity')->where('uid', $param['user_data']['id'])->first();
+                if (empty($userIdentity)) {
+                    throw new \Exception('请实名后,在提现!');
+                }
+                if ($param['mold'] == 1) {
+                    $hasWithdraw = Db::table('wa_withdraw')
+                        ->where('type', $param['mold'])
+                        ->where('binding_type', $param['binding_type'])
+                        ->where('user_id', $param['user_data']['id'])
+                        ->whereBetween('created_at', [date('Y-m-d') . ' 00:00:00', date('Y-m-d') . ' 23:59:59'])->exists();
+                    if ($hasWithdraw) {
+                        throw new \Exception('今日已提现,请次日在来提现!');
+                    }
+                }else{
+                    $hasWithdraw = Db::table('wa_withdraw')->where('type', $param['mold'])->where('user_id', $param['user_data']['id'])
+                        ->whereBetween('created_at', [date('Y-m-d') . ' 00:00:00', date('Y-m-d') . ' 23:59:59'])->exists();
+                    if ($hasWithdraw) {
+                        throw new \Exception('今日已提现,请次日在来提现!');
+                    }
+                }
+
+
+                $withdrawId = Db::table('wa_withdraw')->insertGetId([
+                    'order_no'        => date('YmdHis') . mt_rand(10000, 99999),
+                    'user_id'         => $param['user_data']['id'],
+                    'money'           => $param['money'],
+                    'type'            => $param['mold'],
+                    'affiliated_bank' => $bankCard->affiliated_bank,
+                    'account_holder'  => $bankCard->account_holder,
+                    'card_number'     => $bankCard->card_number,
+                    'name'            => Arr::get($param, 'name', ''),
+                    'identity'        => Arr::get($param, 'identity', ''),
+                    'binding_type'    => Arr::get($param, 'binding_type', 0),
+                    'img'             => !empty(Arr::get($param, 'img', '')) ? implode(',', Arr::get($param, 'img', '')) : '',
+                    'created_at'      => date('Y-m-d H:i:s'),
+                    'updated_at'      => date('Y-m-d H:i:s'),
+                ]);
+                StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType4, $param['mold'], moldTypefild($param['mold']), $withdrawId);
+
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return true;
+
+        }
+
+        /** 提现流水
+         * @param array $param
+         * @return void
+         */
+        static public function stream(array $param)
+        {
+            try {
+                $data = Db::table('wa_withdraw')
+                    ->where(function ($query) use ($param) {
+                        if (!empty(Arr::get($param, 'mold'))) {
+                            $query->where('type', $param['mold']);
+                        }
+                        if (!empty(Arr::get($param, 'type'))) {
+                            if($param['type']==1){
+                                $query->where('type', 1);
+                            }elseif ($param['type']==2){
+                                $query->where('type', 1);
+                                $query->where('binding_type', 1);
+                            }elseif ($param['type']==3){
+                                $query->where('type', 1);
+                                $query->where('binding_type', 2);
+                            }elseif ($param['type']==4){
+                                $query->whereIn('type', [2,5]);
+                            }
+                        }
+                    })
+                    ->where('user_id', $param['user_data']['id'])
+                    ->orderByDesc('id')
+                    ->paginate(Arr::get($param, 'limit', 10), ['*'], 'page', Arr::get($param, 'page'))
+                    ->toArray();
+                foreach ($data['data'] as $k => $v) {
+                    $data['data'][$k]->mold_name = moldType($v->type);
+                }
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return $data;
+        }
+
+
+        /** 转账至五行银行卡
+         * @param array $param
+         * @return void
+         */
+        static public function transfer_accounts(array $param)
+        {
+
+            try {
+                $system = Db::table('wa_system')->first();
+                if ($param['mold'] != 2) {
+                    throw new \Exception('转账至五行银行卡暂未开放!');
+                }
+                $param['mold'] = 5;
+
+                /** @var  $bankCard  银行卡 */
+                $bankCard = Db::table('wa_user_social_cark')->where('user_id', $param['user_data']['id'])->first();
+                if (empty($bankCard)) {
+                    throw new \Exception('请先领取五行银行卡!');
+                }
+                /** @var  $userIdentity  实名信息 */
+                $userIdentity = Db::table('wa_user_identity')->where('uid', $param['user_data']['id'])->first();
+                if (empty($userIdentity)) {
+                    throw new \Exception('请实名后,在转入!');
+                }
+
+                if (empty($system->conversion_value_cost)) {
+                    throw new \Exception('暂时不能转入!');
+                }
+
+                //五行银行卡余额变更
+                $money = bcmul($param['money'], $system->conversion_value_cost, 2);
+                Db::table('wa_user_social_cark')->where('user_id', $param['user_data']['id'])->increment('money', $money);
+
+                //转账到五行银行卡余额
+                StreamBusiness::addStream($param['user_data']['id'], $money, streamType14, moldType4, moldTypefild4);
+
+                //减少股票账户
+                StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType14, $param['mold'], moldTypefild($param['mold']), $param['user_data']['id']);
+
+
+            } catch (\Throwable $exception) {
+                throw new \Exception($exception->getMessage());
+            }
+            return true;
+
+        }
+    }

+ 136 - 0
app/controller/AddressController.php

@@ -0,0 +1,136 @@
+<?php
+
+    namespace app\controller;
+
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+
+    #[Apidoc\Title("地址管理")]
+    #[Apidoc\Group("address")]
+    #[Apidoc\Sort(2)]
+    class AddressController
+    {
+        #[Apidoc\Title("地址列表")]
+        #[Apidoc\Url("api/address.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "name", type: "int", require: true, desc: '收货人', default: '')]
+        #[Apidoc\Returned(name: "mobile", type: "int", require: true, desc: '手机号', default: '')]
+        #[Apidoc\Returned(name: "address", type: "int", require: true, desc: '收货地址', default: '')]
+        public function index(Request $request)
+        {
+            $data = Db::table('wa_address')->where('user_id', $request->user_data['id'])->orderByDesc('id')->get();
+            return success($data);
+        }
+
+        #[Apidoc\Title("新增和更新地址")]
+        #[Apidoc\Url("api/address/add.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("id", type: "int", require: true, desc: "地址ID 没有ID为新增  有ID为更新", mock: 1)]
+        #[Apidoc\Param(name: "name", type: "int", require: true, desc: '收货人', default: '')]
+        #[Apidoc\Param(name: "mobile", type: "int", require: true, desc: '手机号', default: '')]
+        #[Apidoc\Param(name: "address", type: "int", require: true, desc: '收货地址', default: '')]
+        public function add(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'name'    => Validator::notEmpty()->setName('收货人'),
+                    'mobile'  => Validator::notEmpty()->setName('手机号'),
+                    'address' => Validator::notEmpty()->setName('收货地址'),
+                ]);
+                if (empty(Arr::get($param, 'id', ''))) {
+                    Db::table('wa_address')->insert(
+                        [
+                            'user_id' => $request->user_data['id'],
+                            'name'    => Arr::get($param, 'name', ''),
+                            'mobile'  => Arr::get($param, 'mobile', ''),
+                            'address' => Arr::get($param, 'address', ''),
+                        ]
+                    );
+                } else {
+                    $has = Db::table('wa_address')->where('id', $param['id'])->where('user_id', $request->user_data['id'])->first();
+                    if (empty($has)) {
+                        throw new \Exception('非法操作');
+                    }
+                    Db::table('wa_address')->where('id', $param['id'])->where('user_id', $request->user_data['id'])->update([
+                        'name'    => Arr::get($param, 'name', ''),
+                        'mobile'  => Arr::get($param, 'mobile', ''),
+                        'address' => Arr::get($param, 'address', ''),
+                    ]);
+                }
+
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '操作成功');
+        }
+
+        #[Apidoc\Title("删除")]
+        #[Apidoc\Url("api/address/del.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("id", type: "int", require: true, desc: "地址ID", mock: 1)]
+        public function del(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->setName('地址标识'),
+                ]);
+
+                $has = Db::table('wa_address')->where('id', $param['id'])->where('user_id', $request->user_data['id'])->first();
+                if (empty($has)) {
+                    throw new \Exception('非法操作');
+                }
+                Db::table('wa_address')->where('id', $param['id'])->where('user_id', $request->user_data['id'])->delete();
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '操作成功');
+        }
+
+        #[Apidoc\Title("修改地址")]
+        #[Apidoc\Url("api/user/mygoods_saveaddress.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("name", type: "int", require: true, desc: "名称", mock: 1)]
+        #[Apidoc\Param("mobile", type: "int", require: true, desc: "手机号", mock: 1)]
+        #[Apidoc\Param("address", type: "int", require: true, desc: "地址", mock: 1)]
+        public function mygoods_saveaddress(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                $datalist = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+                if (!$datalist) {
+                    throw new \Exception('非法操作');
+                }
+                Db::table('wa_sign_record')->where('id', $datalist->id)->update([
+                    'mobile'  => Arr::get($param, 'mobile', $param['user_data']['mobile']),
+                    'name'    => Arr::get($param, 'name', ''),
+                    'address' => Arr::get($param, 'address', ''),
+                ]);
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '操作成功');
+        }
+
+
+    }

+ 249 - 0
app/controller/BankCardController.php

@@ -0,0 +1,249 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\BankCardBusiness;
+    use app\business\GoodsBusiness;
+    use app\business\StreamBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+
+    #[Apidoc\Title("银行卡管理")]
+    #[Apidoc\Group("Card")]
+    #[Apidoc\Sort(3)]
+    class BankCardController
+    {
+
+
+        #[Apidoc\Title("绑定和修改银行卡信息")]
+        #[Apidoc\Url("api/user/bank_card.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("affiliated_bank", type: "string", require: true, desc: "归属银行", mock: "中国银行")]
+        #[Apidoc\Param("account_holder", type: "string", require: true, desc: "开户人", mock: "张三")]
+        #[Apidoc\Param("card_number", type: "string", require: true, desc: "银行卡号", mock: 500221233312836451)]
+        public function Updata(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'affiliated_bank' => Validator::notEmpty()->stringType()->setName('归属银行'),
+                    'account_holder'  => Validator::notEmpty()->stringType()->setName('开户人'),
+                    'card_number'     => Validator::notEmpty()->setName('银行卡号'),
+                ]);
+                BankCardBusiness::UpData($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success();
+
+
+        }
+
+        #[Apidoc\Title("领取银行卡")]
+        #[Apidoc\Url("api/card/receive_card.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("name", type: "string", require: true, desc: "姓名", mock: "")]
+        #[Apidoc\Param("number", type: "string", require: true, desc: "身份证", mock: "")]
+        #[Apidoc\Param("mobile", type: "string", require: true, desc: "手机号", mock: "")]
+        #[Apidoc\Param("address", type: "string", require: true, desc: "地址", mock: "")]
+        public function receiveCard(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $param              = $request->param_data;
+                $param['user_data'] = $request->user_data;
+//                Validator::input($param, [
+//                    'name'    => Validator::notEmpty()->setName('姓名'),
+//                    'mobile'  => Validator::notEmpty()->setName('手机号'),
+//                    'address' => Validator::notEmpty()->setName('地址'),
+//                ]);
+                $datalist = Db::table('wa_user_social_cark')
+                    ->where('user_id', $param['user_data']['id'])
+                    ->where('type', 1)
+                    ->first();
+                if ($datalist) {
+                    throw new \Exception('已经领取,请不要重复操作!');
+                }
+                $card_num = generateBankAccountNumber();
+                Db::table('wa_user_social_cark')->insert([
+                    'type'       => 2,
+                    'user_id'    => $param['user_data']['id'],
+                    'card_num'   => $card_num,
+                    'password'   => $param['user_data']['password'],
+                    'name'       => Arr::get($param, 'name', $param['user_data']['name']),
+                    'number'     => Arr::get($param, 'number', ''),
+                    'address'    => Arr::get($param, 'address', ''),
+                    'mobile'     => Arr::get($param, 'address', $param['user_data']['mobile']),
+                    'created_at' => date('Y-m-d H:i:s'),
+                    'updated_at' => date('Y-m-d H:i:s'),
+                    'addtime'    => time(),
+                ]);
+                Db::table('wa_users')->where('id', $param['user_data']['id'])->update(['card_code' => $card_num]);
+
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([
+                'card_num' => $card_num,
+                'name'     => Arr::get($param, 'name', $param['user_data']['name']),
+                'number'   => Arr::get($param, 'number', ''),
+                'address'  => Arr::get($param, 'address', ''),
+                'mobile'   => Arr::get($param, 'mobile', $param['user_data']['mobile']),
+            ], '领取成功');
+        }
+
+
+        #[Apidoc\Title("银行卡详情")]
+        #[Apidoc\Url("api/card/card_details.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("type", type: "int", require: false, desc: "类型", mock: '默认:2')]
+        #[Apidoc\Returned(name: "id", type: "string", require: true, desc: 'ID', default: '132')]
+        #[Apidoc\Returned(name: "card_num", type: "string", require: true, desc: '卡号', default: '132')]
+        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '132')]
+        #[Apidoc\Returned(name: "status_name", type: "string", require: true, desc: '状态', default: '132')]
+        #[Apidoc\Returned(name: "money_two", type: "string", require: true, desc: '卡余额', default: '132')]
+        public function cardDetails(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $param              = $request->param_data;
+                $param['user_data'] = $request->user_data;
+
+                $datalist    = Db::table('wa_user_social_cark')
+                    ->where('user_id', $param['user_data']['id'])
+                    ->where('type', 2)
+                    ->select('id', 'card_num', 'name', 'number', 'address', 'mobile', 'status')
+                    ->first();
+                $status_name = '';
+                if ($datalist) {
+                    //状态:1=审核,2=审核完成,3=正在制卡,4=制卡完成,5=等待邮
+                    if ($datalist->status == 1) {
+                        $status_name = '完成';
+                    } elseif ($datalist->status == 2) {
+                        $status_name = '审核中/审核完成/待制卡';
+                    } elseif ($datalist->status == 3) {
+                        $status_name = '审核中/审核完成/正在制卡';
+                    } elseif ($datalist->status == 4) {
+                        $status_name = '审核中/审核完成/正在制卡/制卡完成';
+                    } elseif ($datalist->status == 5) {
+                        $status_name = '审核中/审核完成/正在制卡/制卡完成/等待邮寄';
+                    } elseif ($datalist->status == 6) {
+                        $status_name = '审核中/审核完成/正在制卡/制卡完成/等待邮寄/已发货';
+                    }
+                    $datalist->status_name = $status_name;
+                    $datalist->money_two   = $param['user_data']['money_two'];
+                }
+
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($datalist, '获取成功');
+        }
+
+        #[Apidoc\Title("银行卡地址编辑")]
+        #[Apidoc\Url("api/card/card_address.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("id", type: "int", require: true, desc: "ID", mock: "2")]
+        public function cardAddress(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->setName('id'),
+                ]);
+                $datalist = Db::table('wa_user_social_cark')
+                    ->where('user_id', $param['user_data']['id'])
+                    ->where('id', $param['id'])
+                    ->first();
+                if (!$datalist) {
+                    throw new \Exception('非法操作');
+                }
+                Db::table('wa_user_social_cark')->where('id', $datalist->id)->update([
+                    'mobile'  => Arr::get($param, 'mobile', $param['user_data']['mobile']),
+                    'name'    => Arr::get($param, 'name', $datalist->name),
+                    'number'  => Arr::get($param, 'number', $datalist->number),
+                    'address' => Arr::get($param, 'address', $datalist->address),
+                ]);
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '操作成功');
+
+        }
+
+        #[Apidoc\Title("设置密码")]
+        #[Apidoc\Url("api/card/card_pass.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param(name: "pass_one", type: "int", require: true, desc: '密码', default: '1')]
+        public function cardPass(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $param              = $request->param_data;
+                $param['user_data'] = $request->user_data;
+                Validator::input($param, [
+                    'pass_one' => Validator::notEmpty()->setName('密码'),
+                ]);
+
+                Db::table('wa_users')
+                    ->where('id', $param['user_data']['id'])
+                    ->update(['pass_one' => $param['pass_one']]);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '修改成功');
+        }
+
+        #[Apidoc\Title("获取银行账号")]
+        #[Apidoc\Url("api/card/system.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "account", type: "string", require: true, desc: '开户人', default: '132')]
+        #[Apidoc\Returned(name: "card_number", type: "string", require: true, desc: '卡号', default: '132')]
+        #[Apidoc\Returned(name: "opening_bank", type: "string", require: true, desc: '开户行', default: '132')]
+        public function system(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $system = Db::table('wa_system')->first();
+
+                $data = [
+                    'account'      => $system->account,
+                    'card_number'  => $system->card_number,
+                    'opening_bank' => $system->opening_bank,
+                ];
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($data, '修改成功');
+        }
+
+    }

+ 173 - 0
app/controller/BindingController.php

@@ -0,0 +1,173 @@
+<?php
+
+namespace app\controller;
+
+
+use app\business\GoodsBusiness;
+use app\business\LoginBusiness;
+use app\business\PayorderBusiness;
+use app\business\WithdrawBusiness;
+use Illuminate\Support\Arr;
+use Respect\Validation\Validator;
+use support\Db;
+use support\Redis;
+use support\Request;
+use hg\apidoc\annotation as Apidoc;
+use Webman\Captcha\CaptchaBuilder;
+use Webman\Captcha\PhraseBuilder;
+
+#[Apidoc\Title("绑定")]
+#[Apidoc\Group("Stream")]
+#[Apidoc\Sort(5)]
+class BindingController
+{
+
+    #[Apidoc\Title("绑定支付宝,绑定微信")]
+    #[Apidoc\Url("api/binding.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("account_number", type: "int", require: true, desc: "账号", mock: 10)]
+//        #[Apidoc\Param("mobile", type: "int", require: true, desc: "手机号", mock: 10)]
+    #[Apidoc\Param("type", type: "int", require: true, desc: "类型:1=支付宝,2=微信 ", mock: 2)]
+    #[Apidoc\Param("img", type: "int", require: false, desc: "图片 ", mock: 2)]
+    public function addbinding(Request $request)
+    {
+        $param              = $request->all();
+        $param['user_data'] = $request->user_data;
+        Db::beginTransaction();
+        try {
+            Validator::input($param, [
+                'account_number' => Validator::notEmpty()->setName('账号'),
+                'type'           => Validator::notEmpty()->setName('类型'),
+                'img'           => Validator::notEmpty()->setName('类型'),
+            ]);
+           if(!empty($param['img'])){
+               $base64Image = $param['img'];                                                              // 获取Base64字符串
+               $imageData   = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $base64Image)); // 移除数据URL的前缀并解码
+               $imageName   = time() . '.png';                                                             // 生成一个唯一的文件名
+
+               $data              = '/upload/img/' . date('Ymd');
+               $relative_dir      = ltrim($data, '\\/');
+               $admin_public_path = rtrim(config('app.public_path', ''), '\\/');
+               $base_dir          = $admin_public_path ? $admin_public_path . DIRECTORY_SEPARATOR : base_path() . '/plugin/admin/public/';
+               $full_dir          = $base_dir . $relative_dir;
+               if (!is_dir($full_dir)) {
+                   mkdir($full_dir, 0777, true);
+               }
+               $imagePath = '/upload/img/' . date('Ymd') . '/' . $imageName; // 指定保存路径和文件名
+
+               // 保存图片到服务器
+               file_put_contents($base_dir.$imagePath, $imageData);
+           }else{
+               $imagePath = '';
+           }
+
+            $data = [
+                'user_id'        => $param['user_data']['id'],
+                'account_number' => $param['account_number'],
+                'img'            => $imagePath,
+                'mobile'         => $param['user_data']['mobile'],
+                'type'           => $param['type'],
+                'created_at'     => date('Y-m-d H:i:s'),
+                'updated_at'     => date('Y-m-d H:i:s'),
+            ];
+
+            $binding = Db::table('wa_binding')
+                ->where('user_id', $param['user_data']['id'])
+                ->where('type', $param['type'])
+                ->first();
+            if (empty($binding)) {
+                Db::table('wa_binding')->insert($data);
+            } else {
+                Db::table('wa_binding')->where('id', $binding->id)->update($data);
+            }
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return adminsuccess($data,'绑定成功');
+
+    }
+
+    #[Apidoc\Title("绑定支付宝,绑定微信")]
+    #[Apidoc\Url("api/binding/binding_new.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("wechat_binding", type: "string", require: true, desc: "微信绑定账号", mock: 10)]
+    #[Apidoc\Param("alipay_binding", type: "string", require: true, desc: "支付宝绑定账号", mock: 10)]
+    public function addbinding_new(Request $request)
+    {
+        $param              = $request->param_data;
+        $param['user_data'] = $request->user_data;
+        Db::beginTransaction();
+        try {
+            Validator::input($param, [
+                'wechat_binding' => Validator::notEmpty()->setName('微信绑定账号'),
+                'alipay_binding' => Validator::notEmpty()->setName('支付宝绑定账号'),
+            ]);
+            Db::table('wa_users')
+                ->where('id', $param['user_data']['id'])
+                ->update([
+                    'wechat_binding' => $param['wechat_binding'],
+                    'alipay_binding' => $param['alipay_binding'],
+                    'updated_at'     => date('Y-m-d H:i:s')
+                ]);
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '绑定成功');
+
+    }
+
+    #[Apidoc\Title("绑定记录详情")]
+    #[Apidoc\Url("api/binding/binding_details.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("type", type: "int", require: true, desc: "类型:类型:1=支付宝,2=微信", mock: 2)]
+    #[Apidoc\Returned(name: "account_number", type: "string", require: true, desc: '账号', default: '0.00')]
+    #[Apidoc\Returned(name: "mobile", type: "string", require: true, desc: '手机号', default: '0.00')]
+    public function binding_details(Request $request)
+    {
+        $param              = $request->param_data;
+        $param['user_data'] = $request->user_data;
+        Db::beginTransaction();
+        try {
+            Validator::input($param, [
+                'type' => Validator::notEmpty()->setName('类型'),
+            ]);
+
+            $bindingdata = Db::table('wa_binding')
+                ->where('user_id', $param['user_data']['id'])
+                ->where('type', $param['type'])
+                ->first();
+            if (empty($bindingdata)) {
+                $data = [
+                    'id'             => '',
+                    'account_number' => '',
+                    'mobile'         => '',
+                    'img'            => '',
+                ];
+            } else {
+                $data = [
+                    'id'             => $bindingdata->id,
+                    'account_number' => $bindingdata->account_number,
+                    'mobile'         => $bindingdata->mobile,
+                    'img'            => imageToBase64($bindingdata->img),
+                ];
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($data);
+
+    }
+
+
+}

+ 140 - 0
app/controller/ConfigController.php

@@ -0,0 +1,140 @@
+<?php
+
+    namespace app\controller;
+
+
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+
+    #[Apidoc\Title("配置信息+新闻新闻")]
+    #[Apidoc\Group("Config")]
+    #[Apidoc\Sort(2)]
+    class ConfigController
+    {
+        #[Apidoc\Title("配置")]
+        #[Apidoc\Url("api/config/data.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Returned(name: "association", type: "string", require: true, desc: '社群', default: '')]
+        #[Apidoc\Returned(name: "service", type: "string", require: true, desc: '客服', default: '')]
+        #[Apidoc\Returned(name: "affiche", type: "array", require: true, desc: '公告', default: '')]
+        #[Apidoc\Returned(name: "mp4", type: "string", require: true, desc: '视频', default: '')]
+        #[Apidoc\Returned(name: "company_introduction", type: "string", require: true, desc: '公司介绍', default: '')]
+        #[Apidoc\Returned(name: "corporate_governance", type: "string", require: true, desc: '审查报告', default: '')]
+        #[Apidoc\Returned(name: "public_policy", type: "string", require: true, desc: '公共政策', default: '')]
+        #[Apidoc\Returned(name: "compliance_and_integrity", type: "string", require: true, desc: '合规与诚信', default: '')]
+        #[Apidoc\Returned(name: "intelligent_world", type: "string", require: true, desc: '智能世界', default: '')]
+        #[Apidoc\Returned(name: "micro_chat", type: "string", require: true, desc: '助力微聊', default: '')]
+        #[Apidoc\Returned(name: "booster_potato", type: "string", require: true, desc: '助力土豆', default: '')]
+        #[Apidoc\Returned(name: "service_txt", type: "string", require: true, desc: '客服富文本', default: '')]
+        public function data(Request $request)
+        {
+            $data    = Db::table('wa_system')->first();
+            $affiche = [];
+            if ($data->affiche) {
+                $affiche[] = imgtxt($data->affiche);
+            }
+            if ($data->affiche_one) {
+                $affiche[] = imgtxt($data->affiche_one);
+            }
+            if ($data->affiche_two) {
+                $affiche[] = imgtxt($data->affiche_two);
+            }
+            $articledata = Db::table('wa_article')
+                ->where('article_type_id', 2)
+                ->select(['id', 'name', 'describe', 'img', 'created_at'])
+                ->orderBy('id')
+                ->get()->toArray();
+            return success([
+                'association'              => imgtxt($data->association),
+                'service'                  => $data->service,
+                'affiche'                  => $affiche,
+                'mp4'                      => getenv('MP4'),
+                'company_introduction'     => imgtxt($data->company_introduction),
+                'corporate_governance'     => imgtxt($data->corporate_governance),
+                'public_policy'            => imgtxt($data->public_policy),
+                'compliance_and_integrity' => imgtxt($data->compliance_and_integrity),
+                'intelligent_world'        => imgtxt($data->intelligent_world),
+                'micro_chat'               => $data->micro_chat,
+                'booster_potato'           => $data->booster_potato,
+                'service_txt'              => imgtxt($data->service_txt),
+                'article_data'             => $articledata,
+
+            ]);
+        }
+
+        #[Apidoc\Title("新闻列表")]
+        #[Apidoc\Url("api/config/article.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+        #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+        #[Apidoc\Returned(name: "id", type: "int", require: true, desc: '文章ID', default: '')]
+        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '文章标题', default: '')]
+        #[Apidoc\Returned(name: "describe", type: "string", require: true, desc: '文章描述', default: '')]
+        #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '文章封面图', default: '')]
+        #[Apidoc\Returned(name: "created_at", type: "string", require: true, desc: '创建时间', default: '')]
+        #[Apidoc\Returned(name: "article_type_id", type: "string", require: true, desc: '1=新闻中心,2=热门话题', default: '')]
+        public function article(Request $request)
+        {
+            try {
+                $param = $request->param_data;
+                Validator::input($param, [
+                    'page'  => Validator::notEmpty()->intType()->setName('页面'),
+                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                ]);
+
+                $data = Db::table('wa_article')
+                    ->where('article_type_id', 1)
+                    ->select(['id', 'name', 'describe', 'img', 'created_at'])
+                    ->orderBy('id')
+                    ->paginate(Arr::get($param, 'limit', 10))->toArray();
+                foreach ($data['data'] as $k => $v) {
+                    $data['data'][$k]->img = imageToBase64( $v->img);
+                }
+            } catch (\Throwable $exception) {
+                return error($exception->getMessage());
+            }
+            return success($data);
+        }
+
+        #[Apidoc\Title("新闻详情")]
+        #[Apidoc\Url("api/config/articledetails.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("id", type: "int", require: true, desc: "文章ID", mock: 20)]
+        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '文章标题', default: '')]
+        #[Apidoc\Returned(name: "txt", type: "string", require: true, desc: '文章详情【富文本内容】', default: '')]
+        public function articleDetails(Request $request)
+        {
+            try {
+                $param = $request->param_data;
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->intType()->setName('文章ID'),
+                ]);
+                $data      = Db::table('wa_article')->where('id', $param['id'])->select(['txt', 'name'])->first();
+                $data->txt = imgtxt($data->txt);
+            } catch (\Throwable $exception) {
+                return error($exception->getMessage());
+            }
+            return success($data);
+        }
+
+        #[Apidoc\Title("支付通道")]
+        #[Apidoc\Url("api/config/pay_aisle.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '支付宝')]
+        #[Apidoc\Returned(name: "characteristic", type: "int", require: true, desc: '支付标识', default: '1')]
+        #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '渠道类型', default: '1')]
+        #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '图标', default: '')]
+        public function payAisle()
+        {
+            $data = Db::table('wa_pay_aisle')->where('state', 1)->orderBy('sort')->select(['name', 'characteristic', 'type', 'img'])->get();
+            foreach ($data as $k => $v) {
+                $data[$k]->img = imageToBase64($v->img);
+            }
+            return success($data);
+        }
+
+
+    }

+ 673 - 0
app/controller/GoodsController.php

@@ -0,0 +1,673 @@
+<?php
+
+namespace app\controller;
+
+
+use app\business\GoodsBusiness;
+use app\business\StreamBusiness;
+use Illuminate\Support\Arr;
+use Respect\Validation\Validator;
+use support\Db;
+use support\Request;
+use hg\apidoc\annotation as Apidoc;
+use function Symfony\Component\String\s;
+
+#[Apidoc\Title("项目管理")]
+#[Apidoc\Group("Goods")]
+#[Apidoc\Sort(3)]
+class GoodsController
+{
+    #[Apidoc\Title("列表")]
+    #[Apidoc\Url("api/goods/charity.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+    #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+    #[Apidoc\Param("type", type: "int", require: true, desc: "类型:1=中国供销", mock: 1)]
+    #[Apidoc\Returned(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '')]
+    #[Apidoc\Returned(name: "pay_price", type: "string", require: true, desc: '支付金额', default: '')]
+    #[Apidoc\Returned(name: "bonus", type: "string", require: true, desc: '每日分红', default: '')]
+    #[Apidoc\Returned(name: "balance", type: "string", require: true, desc: '股权数量', default: '')]
+    #[Apidoc\Returned(name: "gift_money", type: "string", require: true, desc: '股权价值', default: '')]
+    #[Apidoc\Returned(name: "daily_limit", type: "string", require: true, desc: '日限额', default: '')]
+    #[Apidoc\Returned(name: "monthly_limit", type: "string", require: true, desc: '月限额', default: '')]
+    #[Apidoc\Returned(name: "is_buy", type: "string", require: true, desc: '是否认购专属股权:true false', default: '')]
+    #[Apidoc\Returned(name: "is_apply_for", type: "string", require: true, desc: '是否已经申请:true=正在邮寄 false=申请邮寄 ', default: '')]
+    #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '图片', default: '')]
+    #[Apidoc\Returned(name: "total_num", type: "int", require: true, desc: '总数', default: '')]
+    #[Apidoc\Returned(name: "num", type: "int", require: true, desc: '剩余数量', default: '')]
+    #[Apidoc\Returned(name: "is_restore", type: "int", require: true, desc: '是否恢复过,0=未恢复,1=已恢复', default: '')]
+    public function charity(Request $request)
+    {
+        try {
+            $param = $request->param_data;
+
+            $data = Db::table('wa_goods')
+                ->where(function ($query) use ($param) {
+                    $query->where('state', 1);
+                    if (Arr::get($param, 'type')) {
+                        $query->where('type', $param['type']);
+                    } else {
+                        $query->where('type', 1);
+                    }
+                })
+                ->orderBy('sort')
+                ->paginate(Arr::get($param, 'limit', 10))
+                ->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]->img    = imageToBase64($v->img);
+                $is_buy                   = Db::table('wa_payorder')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('is_pay', 2)
+                    ->where('goods_id', $v->id)
+                    ->exists();
+                $data['data'][$k]->is_buy = $is_buy ? true : false;
+                $is_apply_for             = Db::table('wa_sign_record')
+                    ->where('uid', $request->user_data['id'])
+                    ->where('goods_id', $v->id)
+                    ->exists();
+                $is_record                = Db::table('wa_sign_record')
+                    ->where('uid', $request->user_data['id'])
+                    ->where('goods_id', $v->id)
+                    ->where('is_restore', 1)
+                    ->first();
+                if ($is_record) {
+                    $data['data'][$k]->is_restore = 1;
+                } else {
+                    $data['data'][$k]->is_restore = 0;
+                }
+                $data['data'][$k]->is_apply_for = $is_apply_for ? true : false;
+
+            }
+        } catch (\Throwable $exception) {
+            return error($exception->getMessage());
+        }
+        return success($data);
+    }
+
+    #[Apidoc\Title("支付")]
+    #[Apidoc\Url("api/goods/charity_buy.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+    #[Apidoc\Param(name: "num", type: "int", require: true, desc: '购买数量:默认1', default: '1')]
+    #[Apidoc\Param(name: "name", type: "string", require: true, desc: '姓名', default: '1')]
+    #[Apidoc\Param(name: "mobile", type: "string", require: true, desc: '手机号', default: '1')]
+    #[Apidoc\Param(name: "number", type: "string", require: true, desc: '身份证', default: '1')]
+    #[Apidoc\Param(name: "address", type: "string", require: true, desc: '地址', default: '1')]
+    #[Apidoc\Param(name: "restore_array", type: "string", require: true, desc: '恢复银行卡ID字符串,逗号隔开', default: '1')]
+    #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型  1直接购买  2支付通道', default: 2)]
+    #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '支付地址', default: 'https://www.baidu.com/')]
+    #[Apidoc\Returned(name: "payOrderId", type: "string", require: true, desc: '订单号', default: '111')]
+    public function charityBuy(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            $param['num']       = Arr::get($param, 'num', 1);
+            Validator::input($param, [
+                'id'                 => Validator::notEmpty()->intType()->setName('产品标识'),
+                'pay_characteristic' => Validator::notEmpty()->setName('支付标识'),
+            ]);
+            $goods = Db::table('wa_goods')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+            if ($goods->type == 4) {
+                Validator::input($param, [
+                    'restore_array' => Validator::notEmpty()->setName('未选择对应恢复银行卡'),
+                ]);
+            }
+
+            $arr = GoodsBusiness::buyType1($param);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '购买成功');
+    }
+
+    #[Apidoc\Title("上传支付凭证")]
+    #[Apidoc\Url("api/goods/voucher_add.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("pay_order_id", type: "int", require: true, desc: "订单ID", mock: 1)]
+    #[Apidoc\Param("img", type: "int", require: true, desc: "凭证图片", mock: 10)]
+    public function voucher_add(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+
+            $param = Arr::only($request->all(), ['pay_order_id', 'img']);
+            Validator::input($param, [
+                'pay_order_id' => Validator::notEmpty()->setName('订单ID'),
+                'img'          => Validator::notEmpty()->setName('图片'),
+            ]);
+            $base64Image = $param['img'];                                                                                           // 获取Base64字符串
+            $imageData   = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $base64Image));                             // 移除数据URL的前缀并解码
+            $imageName   = $request->user_data['id'] . time() . '.png';                                                             // 生成一个唯一的文件名
+
+            $data              = '/upload/img/' . date('Ymd');
+            $relative_dir      = ltrim($data, '\\/');
+            $admin_public_path = rtrim(config('app.public_path', ''), '\\/');
+            $base_dir          = $admin_public_path ? $admin_public_path . DIRECTORY_SEPARATOR : base_path() . '/plugin/admin/public/';
+            $full_dir          = $base_dir . $relative_dir;
+            if (!is_dir($full_dir)) {
+                mkdir($full_dir, 0777, true);
+            }
+            $imagePath = '/upload/img/' . date('Ymd') . '/' . $imageName; // 指定保存路径和文件名
+
+            // 保存图片到服务器
+            file_put_contents($base_dir . $imagePath, $imageData);
+
+            $orderdata = Db::table('wa_payorder')->where('id', $param['pay_order_id'])->first();
+            if (empty($orderdata)) {
+                throw new \Exception('订单不存在!');
+            } else {
+                Db::table('wa_payorder')->where('id', $param['pay_order_id'])->update(['img' => $imagePath, 'updated_at' => date('Y-m-d H:i:s')]);
+            }
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '提交成功');
+    }
+
+
+    #[Apidoc\Title("兑换商品列表")]
+    #[Apidoc\Url("api/goods/exchange_goods.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+    #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+    #[Apidoc\Returned(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '')]
+    #[Apidoc\Returned(name: "pay_price", type: "string", require: true, desc: '支付金额', default: '')]
+    #[Apidoc\Returned(name: "describe", type: "string", require: true, desc: '描述', default: '')]
+    #[Apidoc\Returned(name: "storey", type: "string", require: true, desc: '层数', default: '')]
+    #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '图片', default: '')]
+    #[Apidoc\Returned(name: "total_num", type: "int", require: true, desc: '总数', default: '')]
+    #[Apidoc\Returned(name: "num", type: "int", require: true, desc: '剩余数量', default: '')]
+    public function exchangeGoods(Request $request)
+    {
+        try {
+            $param = Arr::only($request->param_data, ['page', 'limit', 'type']);
+
+            $data = Db::table('wa_sign_goods')
+                ->where(function ($query) use ($param) {
+                    $query->where('state', 1);
+                })
+                ->orderBy('sort')
+                ->paginate(Arr::get($param, 'limit', 10))
+                ->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]->img = imageToBase64($v->img);
+
+            }
+        } catch (\Throwable $exception) {
+            return error($exception->getMessage());
+        }
+        return success($data);
+    }
+
+    #[Apidoc\Title("申领邮寄")]
+    #[Apidoc\Url("api/goods/exchange.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Param("name", type: "int", require: true, desc: '姓名', default: '')]
+    #[Apidoc\Param("mobile", type: "int", require: true, desc: '手机号', default: '')]
+    #[Apidoc\Param("province", type: "int", require: true, desc: '省市区', default: '')]
+    #[Apidoc\Param("address", type: "int", require: true, desc: '详细地址', default: '')]
+    public function exchange(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Validator::input($param, [
+                'id' => Validator::notEmpty()->intType()->setName('产品标识'),
+            ]);
+            $goods = Db::table('wa_goods')->where('id', $param['id'])->first();
+            if (!$goods) {
+                throw new \Exception('数据不存在!');
+            }
+            $is_buy = Db::table('wa_payorder')
+                ->where('user_id', $request->user_data['id'])
+                ->where('is_pay', 2)
+                ->where('goods_id', $param['id'])
+                ->exists();
+            if (!$is_buy) {
+                throw new \Exception('认购专属股权即可申请邮寄!');
+            }
+
+            $card_code = generateBankAccountNumber();
+            Db::table('wa_sign_record')->insert([
+                'uid'        => $param['user_data']['id'],
+                'goods_id'   => $param['id'],
+                'status'     => 1,
+                'card_code'  => $card_code,
+                'name'       => Arr::get($param, 'name', ''),
+                'mobile'     => Arr::get($param, 'mobile', ''),
+                'province'   => Arr::get($param, 'province', ''),
+                'address'    => Arr::get($param, 'address', ''),
+                'created_at' => date('Y-m-d H:i:s'),
+                'updated_at' => date('Y-m-d H:i:s'),
+            ]);
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '兑换成功');
+    }
+
+
+    #[Apidoc\Title("我的卡包")]
+    #[Apidoc\Url("api/goods/exchange_list.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+    #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+    #[Apidoc\Returned(name: "num", type: "int", require: true, desc: '购买数量:默认1', default: '1')]
+    #[Apidoc\Returned(name: "goods_name", type: "int", require: true, desc: '商品名称', default: '')]
+    #[Apidoc\Returned(name: "pay_price", type: "int", require: true, desc: '支付', default: '')]
+    #[Apidoc\Returned(name: "insure_price", type: "int", require: true, desc: '保价价格', default: '')]
+    #[Apidoc\Returned(name: "img", type: "int", require: true, desc: '图片', default: '')]
+    #[Apidoc\Returned(name: "bonus", type: "string", require: true, desc: '每日分红', default: '')]
+    #[Apidoc\Returned(name: "balance", type: "string", require: true, desc: '股权数量', default: '')]
+    #[Apidoc\Returned(name: "gift_money", type: "string", require: true, desc: '股权价值', default: '')]
+    #[Apidoc\Returned(name: "daily_limit", type: "string", require: true, desc: '日限额', default: '')]
+    #[Apidoc\Returned(name: "monthly_limit", type: "string", require: true, desc: '月限额', default: '')]
+    #[Apidoc\Returned(name: "card_code", type: "string", require: true, desc: '卡号', default: '')]
+    #[Apidoc\Returned(name: "status", type: "int", require: true, desc: '状态:1=领取成功,2=发货中,3=已到货', default: '')]
+    #[Apidoc\Returned(name: "status_name", type: "int", require: true, desc: '状态描述', default: '')]
+    #[Apidoc\Returned(name: "name", type: "int", require: true, desc: '姓名', default: '')]
+    #[Apidoc\Returned(name: "mobile", type: "int", require: true, desc: '手机号', default: '')]
+    #[Apidoc\Returned(name: "province", type: "int", require: true, desc: '省市区', default: '')]
+    #[Apidoc\Returned(name: "address", type: "int", require: true, desc: '详细地址', default: '')]
+    #[Apidoc\Returned(name: "is_insure", type: "int", require: true, desc: '是否保价,0=未保价,1=保价', default: '')]
+    public function exchangeList(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+
+            $signdata = Db::table('wa_sign_record')
+                ->where('uid', $param['user_data']['id'])
+                ->where(function ($query) use ($param) {
+                    if (Arr::get($param, 'id')) {
+                        $query->where('id', $param['id']);
+                    }
+                })
+                ->orderByDesc('id')
+                ->paginate(Arr::get($param, 'limit', 10))->toArray();
+            $arr      = [];
+            foreach ($signdata['data'] as $k => $v) {
+                $wa_goods = Db::table('wa_goods')->where('id', $v->goods_id)->first();
+                if ($v->is_pay == 1) {
+                    $status_name = '保密送卡中,待签收';
+                } else {
+                    $status_name = '个税缴纳完成即可邮寄';
+                }
+
+                $is_buy_docking = Db::table('wa_payorder')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('is_pay', 2)
+                    ->where('goods_id', $wa_goods->rebate)
+                    ->exists();
+
+
+                $docking_goods = Db::table('wa_goods')
+                    ->where('id', $wa_goods->rebate)
+                    ->first();
+
+                $pay_goods = Db::table('wa_goods')
+                    ->where('id', $wa_goods->rebate_two)
+                    ->first();
+
+                $zichanxian_price = Db::table('wa_goods')
+                    ->where('id', $wa_goods->rebate_four)
+                    ->value('pay_price');
+
+                $arr[] = [
+                    'good_name'          => $wa_goods->name,
+                    'describe'           => $wa_goods->describe,
+                    'square'             => $wa_goods->square,
+                    'pay_price'          => $wa_goods->pay_price,
+                    'insure_price'       => $wa_goods->insure_price,
+                    'prestore_price'     => $wa_goods->prestore_price,
+                    'jiaona_price'       => $pay_goods->pay_price,
+                    'zichanxian_price'   => $zichanxian_price,
+                    'bonus'              => $wa_goods->bonus,
+                    'balance'            => $wa_goods->balance,
+                    'gift_money'         => $wa_goods->gift_money,
+                    'daily_limit'        => $wa_goods->daily_limit,
+                    'monthly_limit'      => $wa_goods->monthly_limit,
+                    'img'                => imageToBase64($wa_goods->img),
+                    'created_at'         => date('Y-m-d H:i:s', strtotime($v->created_at)),
+                    'id'                 => $v->id,
+                    'status'             => $v->status,
+                    'card_code'          => $v->card_code,
+                    'status_name'        => $status_name,
+                    'name'               => $v->name,
+                    'mobile'             => $v->mobile,
+                    'province'           => $v->province,
+                    'address'            => $v->address,
+                    'is_insure'          => $v->is_insure,
+                    'is_prestore'        => $v->is_prestore,
+                    'is_pay'             => $v->is_pay,
+                    'is_interconnection' => $v->is_interconnection,
+                    'is_asset_insurance' => $v->is_asset_insurance,
+                    'docking_id'         => $docking_goods->id,
+                    'docking_pay_price'  => $docking_goods->pay_price,
+                    'is_buy_docking'     => $is_buy_docking ? true : false,
+                ];
+
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '获取成功');
+    }
+
+
+    #[Apidoc\Title("已经购买恢复")]
+    #[Apidoc\Url("api/goods/buy_restore.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param(name: "name", type: "string", require: true, desc: '姓名', default: '1')]
+    #[Apidoc\Param(name: "mobile", type: "string", require: true, desc: '手机号', default: '1')]
+    #[Apidoc\Param(name: "number", type: "string", require: true, desc: '身份证', default: '1')]
+    #[Apidoc\Param(name: "address", type: "string", require: true, desc: '地址', default: '1')]
+    #[Apidoc\Param(name: "restore_array", type: "string", require: true, desc: '恢复银行卡ID字符串,逗号隔开', default: '1')]
+    public function restore(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Validator::input($param, [
+                'restore_array' => Validator::notEmpty()->setName('恢复ID'),
+            ]);
+            if (!empty($param['restore_array'])) {
+                $restore_array = explode(',', $param['restore_array']);
+                foreach ($restore_array as $k => $v) {
+                    if (!empty($v)) {
+//                        $goods_restore[$k] =  Db::table('wa_sign_record')
+//                            ->where('uid',$param['user_data']['id'])
+//                            ->where('goods_id', $v)
+//                            ->value('is_restore');
+//                        if ($goods_restore[$k] == 1) {
+//                            throw new \Exception('已恢复的银行卡不能重复恢复!');
+//                        }
+                        Db::table('wa_sign_record')->insert([
+                            'uid'        => $param['user_data']['id'],
+                            'goods_id'   => $v,
+                            'status'     => 1,
+                            'is_restore' => 1,
+                            'card_code'  => generateBankAccountNumber(),
+                            'name'       => Arr::get($param, 'name', ''),
+                            'mobile'     => Arr::get($param, 'mobile', ''),
+                            'number'     => Arr::get($param, 'number', ''),
+                            'address'    => Arr::get($param, 'address', ''),
+                            'created_at' => date('Y-m-d H:i:s'),
+                            'updated_at' => date('Y-m-d H:i:s'),
+                        ]);
+                        Db::table('wa_goods')->where('id', $v)->update(['is_restore' => 1]);
+                    }
+                }
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '恢复成功');
+    }
+
+    #[Apidoc\Title("保价支付")]
+    #[Apidoc\Url("api/goods/exchange_buy.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+    #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型  1直接购买  2支付通道', default: 2)]
+    #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '支付地址', default: 'https://www.baidu.com/')]
+    #[Apidoc\Returned(name: "payOrderId", type: "string", require: true, desc: '订单号', default: '111')]
+    public function exchangeBuy(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            $param['num']       = Arr::get($param, 'num', 1);
+            Validator::input($param, [
+                'id'                 => Validator::notEmpty()->intType()->setName('产品标识'),
+                'pay_characteristic' => Validator::notEmpty()->setName('支付标识'),
+            ]);
+            $goods = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('卡不存在!');
+            }
+            $arr = GoodsBusiness::buyType2($param);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '购买成功');
+    }
+
+    #[Apidoc\Title("预存激活支付")]
+    #[Apidoc\Url("api/goods/prestore_buy.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+    #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型  1直接购买  2支付通道', default: 2)]
+    #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '支付地址', default: 'https://www.baidu.com/')]
+    #[Apidoc\Returned(name: "payOrderId", type: "string", require: true, desc: '订单号', default: '111')]
+    public function prestoreBuy(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            $param['num']       = Arr::get($param, 'num', 1);
+            Validator::input($param, [
+                'id'                 => Validator::notEmpty()->intType()->setName('产品标识'),
+                'pay_characteristic' => Validator::notEmpty()->setName('支付标识'),
+            ]);
+            $goods = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('卡不存在!');
+            }
+            $arr = GoodsBusiness::buyType4($param);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '购买成功');
+    }
+
+    #[Apidoc\Title("资产险支付")]
+    #[Apidoc\Url("api/goods/pay_buy.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param(name: "id", type: "int", require: true, desc: '产品ID', default: '')]
+    #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+    #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型  1直接购买  2支付通道', default: 2)]
+    #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '支付地址', default: 'https://www.baidu.com/')]
+    #[Apidoc\Returned(name: "payOrderId", type: "string", require: true, desc: '订单号', default: '111')]
+    public function payBuy(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            $param['num']       = Arr::get($param, 'num', 1);
+            Validator::input($param, [
+                'id'                 => Validator::notEmpty()->intType()->setName('产品标识'),
+                'pay_characteristic' => Validator::notEmpty()->setName('支付标识'),
+            ]);
+            $goods = Db::table('wa_sign_record')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('卡不存在!');
+            }
+            $arr = GoodsBusiness::buyType3($param);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '购买成功');
+    }
+
+//        #[Apidoc\Title("补偿申请")]
+//        #[Apidoc\Url("api/goods/compensation_add.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param(name: "type", type: "int", require: true, desc: '类型:1=企业,2=个人', default: '')]
+//        #[Apidoc\Param(name: "name", type: "int", require: true, desc: '姓名(企业)', default: '')]
+//        #[Apidoc\Param(name: "card_number", type: "int", require: true, desc: '身份证', default: '')]
+//        #[Apidoc\Param(name: "mobile", type: "int", require: true, desc: '手机号', default: '')]
+//        #[Apidoc\Param(name: "province", type: "int", require: true, desc: '省市区', default: '')]
+//        #[Apidoc\Param(name: "address", type: "int", require: true, desc: '详细地址(企业地址)', default: '')]
+//        #[Apidoc\Param(name: "certificate_img", type: "int", require: true, desc: '证书图片', default: '')]
+//        #[Apidoc\Param(name: "report_img", type: "int", require: true, desc: '报表图片', default: '')]
+//        #[Apidoc\Param(name: "scale", type: "int", require: true, desc: '规模', default: '')]
+//        public function compensationAdd(Request $request)
+//        {
+//            Db::beginTransaction();
+//            try {
+//                $param              = $request->all();
+//                $param['user_data'] = $request->user_data;
+//                Validator::input($param, [
+//                    'type' => Validator::notEmpty()->intType()->setName('类型'),
+//                ]);
+//                $applylist = Db::table('wa_apply_record')
+//                    ->where('uid', $param['user_data']['id'])
+//                    ->where('type', $param['type'])
+//                    ->first();
+//                if ($applylist) {
+//                    if ($applylist->status == 3) {
+//                        $applyID = Db::table('wa_apply_record')->where('id', $applylist->id)->update([
+//                            'uid'             => $param['user_data']['id'],
+//                            'type'            => $param['type'],
+//                            'money'           => $applylist->money,
+//                            'name'            => Arr::get($param, 'name', null),
+//                            'mobile'          => Arr::get($param, 'mobile', null),
+//                            'card_number'     => Arr::get($param, 'card_number', null),
+//                            'province'        => Arr::get($param, 'province', null),
+//                            'address'         => Arr::get($param, 'address', null),
+//                            'certificate_img' => Arr::get($param, 'certificate_img', null),
+//                            'report_img'      => Arr::get($param, 'report_img', null),
+//                            'scale'           => Arr::get($param, 'scale', null),
+//                            'created_at'      => date('Y-m-d H:i:s'),
+//                            'updated_at'      => date('Y-m-d H:i:s'),
+//                            'add_time'        => bcadd(time(), '10800'),
+//                            'status'          => 1
+//                        ]);
+//                    } else {
+//                        throw new \Exception('已经申领过了!');
+//                    }
+//                } else {
+//                    $applyID = Db::table('wa_apply_record')->insertGetId([
+//                        'uid'             => $param['user_data']['id'],
+//                        'type'            => $param['type'],
+//                        'money'           => mt_rand(1080000, 1880000),
+//                        'name'            => Arr::get($param, 'name', null),
+//                        'mobile'          => Arr::get($param, 'mobile', null),
+//                        'card_number'     => Arr::get($param, 'card_number', null),
+//                        'province'        => Arr::get($param, 'province', null),
+//                        'address'         => Arr::get($param, 'address', null),
+//                        'certificate_img' => Arr::get($param, 'certificate_img', null),
+//                        'report_img'      => Arr::get($param, 'report_img', null),
+//                        'scale'           => Arr::get($param, 'scale', null),
+//                        'created_at'      => date('Y-m-d H:i:s'),
+//                        'updated_at'      => date('Y-m-d H:i:s'),
+//                        'add_time'        => bcadd(time(), '10800')
+//                    ]);
+//                }
+//
+//
+//            } catch (\Throwable $exception) {
+//                Db::rollBack();
+//                return error($exception->getMessage());
+//            }
+//            Db::commit();
+//            return success([], '补偿申领成功');
+//        }
+//
+//
+//        #[Apidoc\Title("补偿申请详情")]
+//        #[Apidoc\Url("api/goods/compensation_details.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param(name: "type", type: "int", require: true, desc: '类型:1=企业,2=个人', default: '')]
+//        #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型:1=企业,2=个人', default: '')]
+//        #[Apidoc\Returned(name: "name", type: "int", require: true, desc: '姓名(企业)', default: '')]
+//        #[Apidoc\Returned(name: "card_number", type: "int", require: true, desc: '身份证', default: '')]
+//        #[Apidoc\Returned(name: "mobile", type: "int", require: true, desc: '手机号', default: '')]
+//        #[Apidoc\Returned(name: "province", type: "int", require: true, desc: '省市区', default: '')]
+//        #[Apidoc\Returned(name: "address", type: "int", require: true, desc: '详细地址(企业地址)', default: '')]
+//        #[Apidoc\Returned(name: "certificate_img", type: "int", require: true, desc: '证书图片', default: '')]
+//        #[Apidoc\Returned(name: "report_img", type: "int", require: true, desc: '报表图片', default: '')]
+//        #[Apidoc\Returned(name: "scale", type: "int", require: true, desc: '规模', default: '')]
+//        #[Apidoc\Returned(name: "status", type: "int", require: true, desc: '状态: 1=待审核,2=审核通过,3=驳回', default: '')]
+//        #[Apidoc\Returned(name: "report_img_array", type: "int", require: true, desc: '报表图片数组', default: '')]
+//        public function compensationDetails(Request $request)
+//        {
+//            Db::beginTransaction();
+//            try {
+//                $param              = $request->all();
+//                $param['user_data'] = $request->user_data;
+//                Validator::input($param, [
+//                    'type' => Validator::notEmpty()->intType()->setName('类型'),
+//                ]);
+//                $applylist = Db::table('wa_apply_record')
+//                    ->where('uid', $param['user_data']['id'])
+//                    ->where('type', $param['type'])
+//                    ->first();
+//                if (!$applylist) {
+//                    Db::rollBack();
+//                    return success('', '数据不存在');
+//
+//                }
+//                if (!empty($applylist->certificate_img)) {
+//                    $applylist->certificate_img = getenv('IMG') . $applylist->certificate_img;
+//                }
+//                if (!empty($applylist->report_img)) {
+//                    $report_img = explode(',', $applylist->report_img);
+//                    $array_img  = [];
+//                    foreach ($report_img as $k => $v) {
+//                        $array_img[] = getenv('IMG') . $v;
+//                    }
+//                    $applylist->report_img       = $applylist->report_img;
+//                    $applylist->report_img_array = $array_img;
+//                }
+//
+//            } catch (\Throwable $exception) {
+//                Db::rollBack();
+//                return error($exception->getMessage());
+//            }
+//            Db::commit();
+//            return success($applylist, '补偿申领成功');
+//        }
+
+
+}

+ 66 - 0
app/controller/IssueController.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace app\controller;
+use app\business\StreamBusiness;
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Log;
+use support\Request;
+
+class IssueController
+{
+    public function index(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('issue')->info('接口回调',$param);
+        Db::beginTransaction();
+        try {
+            $order=Db::table('wa_withdraw')->where('order_no',$param['mchOrderNo'])->first();
+            if(empty($order)){
+                throw new \Exception('订单号不存在!');
+            }
+            if($order->status != 2){
+                throw new \Exception('当前订单已处理!');
+            }
+            if(Arr::get($param,'status') == 2){
+                $status  =   3;
+            }else{
+                if (empty($order)) {
+                    throw new \Exception('暂无订单');
+                }
+                if ($order->status != 2) {
+                    throw new \Exception('【' . $order->order_no . '】已被审核!');
+                }
+//
+//                if ($order->type == 1) {
+//                    $mold = moldType1;
+//                    $moldfield = moldTypefild1;
+//                } elseif ($order->type == 2) {
+//                    $mold = moldType2;
+//                    $moldfield = moldTypefild2;
+//                } elseif ($order->type == 3) {
+//                    $mold = moldType3;
+//                    $moldfield = moldTypefild3;
+//                } elseif ($order->type == 4) {
+//                    $mold = moldType4;
+//                    $moldfield = moldTypefild4;
+//                } elseif ($order->type == 4) {
+//                    $mold = moldType4;
+//                    $moldfield = moldTypefild4;
+//                }
+                StreamBusiness::addStream($order->user_id,  $order->money, streamType6, $order->type, moldTypefild($order->type),$order->id);
+                $status = 4;
+            }
+            Db::table('wa_withdraw')->where('id',$order->id)->update(['status'=>$status]);
+
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('issue')->error('接口回调'.$exception->getMessage(),$param);
+        }
+
+        return "success";
+    }
+
+
+}

+ 316 - 0
app/controller/LoginController.php

@@ -0,0 +1,316 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\LoginBusiness;
+    use app\business\SmsBusiness;
+    use app\business\StreamBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    #[Apidoc\Title("登陆注册")]
+    #[Apidoc\Group("Login")]
+    #[Apidoc\Sort(1)]
+    class LoginController
+    {
+        #[Apidoc\Title("登录")]
+        #[Apidoc\Url("api/login/login.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("mobile", type: "int", require: true, desc: "账号/手机号", mock: 16500000000)]
+        #[Apidoc\Param("app", type: "int", require: true, desc: "是否为APP", mock: '')]
+        #[Apidoc\Param("password", type: "string", require: true, desc: "密码(6-16字母加数字)位密码", mock: 123456)]
+        #[Apidoc\Param("code", type: "int", require: true, desc: "验证码")]
+        #[Apidoc\Param("key", type: "string", require: true, desc: "验证码的key")]
+        public function login(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                $param = Arr::only($param, ['mobile', 'password', 'app', 'code', 'key']);
+                Validator::input($param, [
+                    'mobile'   => Validator::notEmpty()->intType()->setName('手机号'),
+                    'password' => Validator::notEmpty()->stringType()->Length(6, 15)->alnum()->setName('密码'),
+//                    'code'     => Validator::notEmpty()->intType()->setName('验证码'),
+//                    'key'      => Validator::notEmpty()->stringType()->setName('验证码标识'),
+                ]);
+                /* if(empty(preg_match('/^1[3-9]\d{9}$/', $param['mobile']))){
+                     throw new \Exception('请输入正确的手机号');
+                 }*/
+//                if (strtolower($param['code']) != Redis::get($param['key'])) {
+//                    throw new \Exception('验证码错误!');
+//                }
+                $param['last_ip'] = $request->getRealIp($safe_mode = true);
+                $token            = LoginBusiness::login($param);
+                Redis::del($param['key']);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([
+                'token' => $token
+            ]);
+
+        }
+
+        #[Apidoc\Title("注册")]
+        #[Apidoc\Url("api/login/register.html")]
+        #[Apidoc\Method("POST")]
+        // #[Apidoc\Header("token",type: "string",require: true,desc: "身份令牌Token",mock: "@token")]
+        #[Apidoc\Param("mobile", type: "int", require: true, desc: "账号/手机号", mock: 15800000000)]
+        #[Apidoc\Param("password", type: "string", require: true, desc: "密码(6-16字母加数字)位密码", mock: 123456)]
+        #[Apidoc\Param("confirm_password", type: "string", require: true, desc: "确认密码(6-16字母加数字)位密码", mock: 123456)]
+        #[Apidoc\Param("invitation_code", type: "int", require: true, desc: "邀请码", mock: 100001)]
+        #[Apidoc\Param("code", type: "int", require: true, desc: "验证码")]
+        #[Apidoc\Param("key", type: "string", require: true, desc: "验证码的key")]
+        public function register(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                $param = Arr::only($param, ['mobile', 'password', 'confirm_password', 'invitation_code', 'code', 'key']);
+                Validator::input($param, [
+                    'mobile'           => Validator::notEmpty()->intType()->setName('手机号'),
+                    'password'         => Validator::notEmpty()->stringType()->Length(6, 15)->alnum()->setName('密码'),
+                    'confirm_password' => Validator::notEmpty()->stringType()->Length(6, 15)->alnum()->setName('确认密码'),
+                    'invitation_code'  => Validator::notEmpty()->intType()->setName('邀请码'),
+                    'code'             => Validator::notEmpty()->intType()->setName('验证码'),
+                    'key'              => Validator::notEmpty()->stringType()->setName('验证码标识'),
+                ]);
+                /*  if(empty(preg_match('/^1[3-9]\d{9}$/', $param['mobile']))){
+                      throw new \Exception('请输入正确的手机号');
+                  }
+                */
+                if (strtolower($param['code']) != Redis::get($param['key'])) {
+                    throw new \Exception('验证码错误!');
+                }
+                Redis::del($param['key']);
+                if ($param['password'] != $param['confirm_password']) {
+                    throw new \Exception('两次密码不一致!');
+                }
+                $param['last_ip'] = $request->getRealIp($safe_mode = true);
+                $param['join_ip'] = $param['last_ip'];
+                $token            = LoginBusiness::register($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([
+                'token' => $token
+            ]);
+        }
+
+//        #[Apidoc\Title("注册领取")]
+//        #[Apidoc\Url("api/login/register_receive.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        public function register_receive(Request $request)
+//        {
+//            $param = $request->all();
+//            Db::beginTransaction();
+//            try {
+//                $user   = Db::table('wa_users')->where('id', $request->user_data['id'])->first();
+//                $system = Db::table('wa_system')->first();
+//                /** @var  $has 查是否已经领取 */
+//                $has = Db::table('wa_stream')
+//                    ->where('user_id', $request->user_data['id'])
+//                    ->where('type', streamType1)
+//                    ->where('mold', moldType5)
+//                    ->exists();
+//                if (!empty($has)) {
+//                    throw new \Exception('已经领取该奖励了,不能重复领取!');
+//                }
+//
+//                /** 注册赠送 */
+//                if (!empty($system) && !empty($user) && !empty($system->register_award)) {//注册赠送
+//                    StreamBusiness::addStream($request->user_data['id'], $system->register_award, streamType1, moldType5, moldTypefild5);
+//                }
+//            } catch (\Throwable $exception) {
+//                Db::rollBack();
+//                return error($exception->getMessage());
+//            }
+//            Db::commit();
+//            return success([], '领取成功');
+//        }
+
+
+        #[Apidoc\Title("验证码")]
+        #[Apidoc\Url("api/login/authccode.html")]
+        #[Apidoc\Method("POST")]
+        // #[Apidoc\Header("token",type: "string",require: true,desc: "身份令牌Token",mock: "@token")]
+        #[Apidoc\Returned(name: "img", type: "blob", require: true, desc: '图形验证码', default: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7')]
+        #[Apidoc\Returned(name: "key", type: "string", require: true, desc: '验证码KEY', default: 'authccode172036979253337')]
+        public function authccode()
+        {
+            $phraseBuilder = new PhraseBuilder(4, '123456789');
+            $builder       = new CaptchaBuilder(null, $phraseBuilder);
+            // 生成验证码
+            $builder->build(100, 29);
+            $key = 'authccode' . time() . mt_rand(10000, 99999);
+            Redis::setEx($key, 600, strtolower($builder->getPhrase()));
+            $img_content = $builder->inline();
+            return success(['img' => $img_content, 'key' => $key]);
+        }
+
+        #[Apidoc\Title("邀请规则")]
+        #[Apidoc\Url("api/login/invite.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "invite", type: "array", desc: '活动规则', default: '', children: [
+            ['name' => "id", 'type' => 'int', 'require' => true, 'default' => 1, 'desc' => '规则ID'],
+            ['name' => "num", 'type' => 'int', 'require' => true, 'default' => 1, 'desc' => '邀请人'],
+            ['name' => "money", 'type' => 'int', 'require' => true, 'default' => 38, 'desc' => '农业补贴金'],
+            ['name' => "complete", 'type' => 'int', 'require' => true, 'default' => 0, 'desc' => '完成人数'],
+            ['name' => "has", 'type' => 'int', 'require' => true, 'default' => false, 'desc' => '是否领奖 true  已领奖  false 未领奖'],
+        ])]
+        #[Apidoc\Returned(name: "uuid", type: "string", require: true, desc: '邀请码', default: '10001')]
+        #[Apidoc\Returned(name: "is_num", type: "string", require: true, desc: '累计邀请人数', default: '10001')]
+        #[Apidoc\Returned(name: "invitation_award", type: "int", require: true, desc: '邀请奖励', default: 'trun')]
+        public function invite(Request $request)
+        {
+            $invite = Db::table('wa_invite')->where('status', 1)
+                ->select(['id', 'num', 'money', 'money_two', 'money_one'])
+                ->orderBy('sort')->get()->toArray();
+            foreach ($invite as $k => $v) {
+                $invite[$k]->complete = $request->user_data['is_num'];
+                $invite[$k]->has      = Db::table('wa_stream')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('type', streamType3)
+                    ->where('source_id', $v->id)->exists();
+            }
+
+            $system = Db::table('wa_system')->first();
+            return success([
+                'invite'           => $invite,
+                'uuid'             => $request->user_data['uuid'],
+                'is_num'           => $request->user_data['is_num'],
+                'invitation_award' => $system->invitation_award,
+            ]);
+        }
+
+        #[Apidoc\Title("邀请领奖")]
+        #[Apidoc\Url("api/login/invite_receive.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("id", type: "int", require: true, desc: '邀请规则ID', mock: 1)]
+        public function invite_receive(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                $param = Arr::only($param, ['id']);
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->intType()->setName('标识'),
+                ]);
+                $inviteData = Db::table('wa_invite')->where('id', $param['id'])->first();
+                if (empty($inviteData)) {
+                    throw new \Exception('非法操作');
+                }
+                if ($request->user_data['is_num'] < $inviteData->num) {
+                    throw new \Exception('未达到,邀请规则!');
+                }
+                $has = Db::table('wa_stream')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('type', streamType3)
+                    ->where('source_id', $param['id'])
+                    ->exists();
+                if (!empty($has)) {
+                    throw new \Exception('已领取过奖励!');
+                }
+                if (!empty($inviteData->money)) {
+                    //农业补贴金
+                    StreamBusiness::addStream($request->user_data['id'], $inviteData->money, streamType3, moldType3, moldTypefild3, $inviteData->id);
+                }
+                if (!empty($inviteData->money_one)) {
+                    //中国粮仓支票
+                    StreamBusiness::addStream($request->user_data['id'], $inviteData->money_one, streamType3, moldType2, moldTypefild2, $inviteData->id);
+                }
+
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '领取成功');
+        }
+
+        #[Apidoc\Title("判断当前用户是否存在是否实名")]
+        #[Apidoc\Url("api/login/sign_in.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("mobile", type: "int", require: true, desc: "账号/手机号", mock: 15800000000)]
+        #[Apidoc\Returned(name: "is_sign_in", type: "int", require: true, desc: '是否实名 1=未实名,2=实名', default: '1')]
+        public function signIn(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                $param = Arr::only($param, ['mobile']);
+                Validator::input($param, [
+                    'mobile' => Validator::notEmpty()->intType()->setName('手机号'),
+                ]);
+                $userlist = Db::table('wa_users')->where('mobile', $param['mobile'])->first();
+                if (!$userlist) {
+                    throw new \Exception('请输入正确手机号!');
+                }
+                $is_sign_in = 1;
+                if ($userlist->is_autonym == 1) {
+                    $is_sign_in = 2;
+                }
+                $data = ['is_sign_in' => $is_sign_in];
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($data, '请求成功');
+        }
+
+        #[Apidoc\Title("未登陆修改密码")]
+        #[Apidoc\Url("api/login/passsave.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("mobile", type: "int", require: true, desc: "手机号", mock: 15800000000)]
+        #[Apidoc\Param("number", type: "string", require: true, desc: "身份证", mock: 1123)]
+        #[Apidoc\Param("password", type: "int", require: true, desc: "密码", mock: 123456)]
+        public function passsave(Request $request)
+        {
+            $param = $request->param_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'mobile'   => Validator::notEmpty()->intType()->setName('手机号'),
+                    'password' => Validator::notEmpty()->setName('密码'),
+                ]);
+                $userlist = Db::table('wa_users')->where('mobile', $param['mobile'])->first();
+                if (!$userlist) {
+                    throw new \Exception('请输入正确手机号!');
+                }
+                if ($userlist->is_autonym == 1) {
+                    if (empty($param['number'])) {
+                        throw new \Exception('请输入身份证号码!');
+                    }
+                    $identity = Db::table('wa_user_identity')->where('uid', $userlist->id)->where('number', $param['number'])->first();
+                    if (!$identity) {
+                        throw new \Exception('输入的身份证号码和实名信息不一致!');
+                    }
+                }
+                Db::table('wa_users')->where('id', $userlist->id)->update(['password' => md5($param['password'])]);
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '修改成功');
+        }
+
+    }

+ 148 - 0
app/controller/MyGoodsController.php

@@ -0,0 +1,148 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\GoodsBusiness;
+    use app\business\LoginBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    #[Apidoc\Title("投资记录")]
+    #[Apidoc\Group("Goods")]
+    #[Apidoc\Sort(3)]
+    class MyGoodsController
+    {
+        #[Apidoc\Title("投资记录列表")]
+        #[Apidoc\Url("api/user/mygoods.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+        #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+        #[Apidoc\Returned(name: "good_name", type: "string", require: true, desc: '商品名称', default: '')]
+        #[Apidoc\Returned(name: "pay_price", type: "string", require: true, desc: '商品单价', default: '')]
+        #[Apidoc\Returned(name: "money", type: "string", require: true, desc: '支付金额', default: '')]
+        #[Apidoc\Returned(name: "bonus", type: "string", require: true, desc: '每天税后', default: '')]
+        #[Apidoc\Returned(name: "balance", type: "string", require: true, desc: '股权数量', default: '')]
+        #[Apidoc\Returned(name: "gift_money", type: "string", require: true, desc: '股权价值', default: '')]
+        #[Apidoc\Returned(name: "daily_limit", type: "string", require: true, desc: '日限额', default: '')]
+        #[Apidoc\Returned(name: "monthly_limit", type: "string", require: true, desc: '月限额', default: '')]
+        #[Apidoc\Returned(name: "created_at", type: "string", require: true, desc: '购买时间', default: '')]
+        #[Apidoc\Returned(name: "status", type: "string", require: true, desc: '状态  1正常  2失效  3终止', default: '')]
+        public function index(Request $request)
+        {
+            $param = $request->param_data;
+            try {
+                Validator::input($param, [
+                    'page'  => Validator::notEmpty()->intType()->setName('页面'),
+                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                ]);
+                $data = Db::table('wa_my_goods')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where(function ($query) use ($param) {
+                        if (Arr::get($param, 'type')) {
+                            $query->where('type', $param['type']);
+                        }
+                    })
+                    ->orderByDesc('id')
+                    ->paginate(Arr::get($param, 'limit', 10), ['*'], 'page', Arr::get($param, 'page'))
+                    ->toArray();
+                $arr  = [];
+                foreach ($data['data'] as $k => $v) {
+                    $wa_goods = Db::table('wa_goods')->where('id', $v->goods_id)->first();
+                    $arr[]    = [
+                        'good_name'     => $wa_goods->name,
+                        'pay_price'     => $wa_goods->pay_price,
+                        'bonus'         => $wa_goods->bonus,
+                        'balance'       => $wa_goods->balance,
+                        'gift_money'    => $wa_goods->gift_money,
+                        'daily_limit'   => $wa_goods->daily_limit,
+                        'monthly_limit' => $wa_goods->monthly_limit,
+                        'img'           => imageToBase64($wa_goods->img),
+                        'created_at'    => date('Y-m-d H:i:s', strtotime($v->created_at)),
+                        'id'            => $v->id,
+                        'num'           => $v->num,
+                        'money'         => $v->money,
+                        'status'        => $v->status,
+                        'name'          => $v->name,
+                        'mobile'        => $v->mobile,
+                        'address'       => $v->address,
+                        'send_status'   => $v->send_status,
+                        'pass'          => $v->pass,
+                        'type'          => $v->type,
+                    ];
+                }
+            } catch (\Throwable $exception) {
+                return error($exception->getMessage());
+            }
+            return success($arr, '成功', 200, $data['total']);
+        }
+
+
+//        #[Apidoc\Title("发货记录列表")]
+//        #[Apidoc\Url("api/user/deliverygoods.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+//        #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+//        #[Apidoc\Returned(name: "good_name", type: "string", require: true, desc: '商品名称', default: '')]
+//        #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '图片', default: '')]
+//        #[Apidoc\Returned(name: "bonus", type: "string", require: true, desc: '赠送', default: '')]
+//        #[Apidoc\Returned(name: "pay_price", type: "string", require: true, desc: '支付金额', default: '')]
+//        #[Apidoc\Returned(name: "created_at", type: "string", require: true, desc: '购买时间', default: '')]
+//        #[Apidoc\Returned(name: "send_status", type: "string", require: true, desc: '发货状态:1=领取成功,2=发货中,3=已到货', default: '')]
+//        #[Apidoc\Returned(name: "status", type: "string", require: true, desc: '状态  1正常  2失效  3终止', default: '')]
+//        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '')]
+//        #[Apidoc\Returned(name: "mobile", type: "string", require: true, desc: '手机号', default: '')]
+//        #[Apidoc\Returned(name: "address", type: "string", require: true, desc: '地址', default: '')]
+//        public function deliverygoods(Request $request)
+//        {
+//            $param = $request->param_data;
+//            try {
+//                Validator::input($param, [
+//                    'page'  => Validator::notEmpty()->intType()->setName('页面'),
+//                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+//                ]);
+//                $data = Db::table('wa_my_goods')
+//                    ->where('user_id', $request->user_data['id'])
+//                    ->where(function ($query) use ($param) {
+////                        if (Arr::get($param, 'type')) {
+////                            $query->where('type', $param['type']);
+////                        }
+//                        $query->whereIn('type', [0, 3, 4]);
+//                    })
+//                    ->orderByDesc('id')
+//                    ->paginate(Arr::get($param, 'limit', 1))
+//                    ->toArray();
+//                $arr  = [];
+//                foreach ($data['data'] as $k => $v) {
+//                    $wa_goods = Db::table('wa_goods')->where('id', $v->goods_id)->first();
+//                    $arr[]    = [
+//                        'good_name'   => $wa_goods->name,
+//                        'bonus'       => $wa_goods->bonus,
+//                        'img'         => imageToBase64($wa_goods->img),
+//                        'created_at'  => date('Y-m-d H:i:s', strtotime($v->created_at)),
+//                        'id'          => $v->id,
+//                        'num'         => $v->num,
+//                        'money'       => $v->money,
+//                        'status'      => $v->status,
+//                        'name'        => $v->name,
+//                        'mobile'      => $v->mobile,
+//                        'address'     => $v->address,
+//                        'type'        => $v->type,
+//                        'send_status' => $v->send_status,
+//                    ];
+//                }
+//            } catch (\Throwable $exception) {
+//                return error($exception->getMessage());
+//            }
+//            return success($arr, '成功', 200, $data['total']);
+//        }
+
+    }

+ 95 - 0
app/controller/PayController.php

@@ -0,0 +1,95 @@
+<?php
+
+namespace app\controller;
+
+use app\business\GoodsBusiness;
+use app\business\PayorderBusiness;
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Log;
+use support\Request;
+
+
+class PayController
+{
+    public function paymentCallback(Request $request)
+    {
+        $param=$request->all();
+//        $data=Arr::only($param,['amount','outOrderNum','orderNum','mchNum','timeStamp','status']);
+        Log::channel('paymentCallback')->info('拉丁-充值回调:',$param);
+        Db::beginTransaction();
+        try {
+           /* $sign=GoodsBusiness::payMd5sign($data);
+            if($sign != $param['sign']){
+                throw new \Exception('签名错误!');
+            }*/
+            PayorderBusiness::paymentCallback($param['outOrderNum']);
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('paymentCallback')->error('拉丁-充值回调报错:'.$exception->getMessage(),$param);
+        }
+        return "success";
+    }
+    /** 桥头支付回调
+     * @param Request $request
+     * @return string
+     */
+    public function paymentCallbackTwo(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('paymentCallback')->info('桥头-充值回调:',$param);
+        Db::beginTransaction();
+        try {
+            PayorderBusiness::paymentCallback($param['mchOrderNo']);
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('paymentCallback')->error('桥头-充值回调报错:'.$exception->getMessage(),$param);
+        }
+        return "success";
+    }
+
+    /** 林北支付回调
+     * @param Request $request
+     * @return string
+     */
+    public function paymentCallbackThree(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('paymentCallback')->info('林北-充值回调:',$param);
+        Db::beginTransaction();
+        try {
+            if ($param['orderStatus'] != 'AP') {
+                throw new \Exception('支付异常!');
+            }
+            PayorderBusiness::paymentCallback($param['callerOrderId']);
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('paymentCallback')->error('林北-充值回调报错:'.$exception->getMessage(),$param);
+        }
+        return "OK";
+    }
+
+    /** 鸿运支付回调
+     * @param Request $request
+     * @return string
+     */
+    public function payment_callback_five(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('paymentCallback')->info('鸿运-充值回调:',$param);
+        Db::beginTransaction();
+        try {
+            PayorderBusiness::paymentCallback($param['mchOrderNo']);
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            Log::channel('paymentCallback')->error('鸿运-充值回调报错:'.$exception->getMessage(),$param);
+        }
+        return "success";
+    }
+
+
+}

+ 178 - 0
app/controller/RaffleController.php

@@ -0,0 +1,178 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\LoginBusiness;
+    use app\business\StreamBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+//    #[Apidoc\Title("抽奖管理")]
+//    #[Apidoc\Group("Login")]
+//    #[Apidoc\Sort(1)]
+    class RaffleController
+    {
+
+        #[Apidoc\Title("抽奖列表")]
+        #[Apidoc\Url("api/raffle.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "raffle_num", type: "int", require: true, desc: '抽奖次数', default: 10)]
+        #[Apidoc\Returned(name: "accumulate_raffle_num", type: "int", require: true, desc: '累计抽奖次数', default: 10)]
+        #[Apidoc\Returned(name: "raffle", type: "array", desc: '抽奖列表', default: '', children: [
+            ['name' => "id", 'type' => 'int', 'require' => true, 'default' => '奖励标识,抽奖结果会返回', 'desc' => 1],
+            ['name' => "name", 'type' => 'int', 'require' => true, 'default' => '获奖名称', 'desc' => 1],
+            ['name' => "img", 'type' => 'int', 'require' => true, 'default' => '获奖图片', 'desc' => 1],
+            ['name' => "money", 'type' => 'int', 'require' => true, 'default' => '中奖积分', 'desc' => 1],
+        ])]
+        public function index(Request $request)
+        {
+            $data = Db::table('wa_raffle')
+                ->where('status', 1)
+                ->select(['id', 'money', 'img', 'name'])
+                ->orderBy('sort')
+                ->get()->toArray();
+            foreach ($data as $k => $v) {
+                $data[$k]->img = imageToBase64($v->img);
+            }
+            return success([
+                'raffle'                => $data,
+                'raffle_num'            => $request->user_data['raffle_num'],
+                'accumulate_raffle_num' => $request->user_data['accumulate_raffle_num']
+            ], '获取成功');
+        }
+
+        #[Apidoc\Title("抽奖")]
+        #[Apidoc\Url("api/raffle/buy.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "id", type: "int", require: true, desc: '奖品ID', default: 10)]
+        #[Apidoc\Returned(name: "name", type: "int", require: true, desc: '名称', default: 10)]
+        #[Apidoc\Returned(name: "img", type: "int", require: true, desc: '图片', default: 10)]
+        public function buy(Request $request)
+        {
+            Db::beginTransaction();
+
+            try {
+                if ($request->user_data['raffle_num'] <= 0) {
+                    throw new \Exception('你当前没有抽奖次数了');
+                }
+                $prize_list = Db::table('wa_raffle')->where('status', 1)->get()->toArray();
+                $arr        = [];
+                foreach ($prize_list as $key => $vo) {
+                    if ($vo->pro >= 1) {
+                        for ($i = 1; $i <= $vo->pro; $i ++) {
+                            array_push($arr, (int)$vo->id);
+                        }
+                    }
+                }
+                //随机打算数组内中奖id的顺序
+                shuffle($arr);
+                $lucky_index = array_rand($arr, 1);          //随机从中奖的集合中获取一个中奖的元素(这里返回的是当前元素所在的索引)
+                $lucky_id    = $arr[$lucky_index];           //这里最终确定了抽中的奖品id
+
+                Db::table('wa_raffle_log')->insertGetId([
+                    'user_id'    => $request->user_data['id'],
+                    'raffle_id'  => $lucky_id,
+                    'created_at' => date("Y-m-d H:i:s"),
+                ]);
+                $raffledata = Db::table('wa_raffle')->where('id', $lucky_id)->first();
+                if(!empty($raffledata->money)){
+                    StreamBusiness::addStream($request->user_data['id'], $raffledata->money, streamType12, moldType5, moldTypefild5);
+                }
+
+                /** 减少抽奖次数 */
+                Db::table('wa_users')->where('id', $request->user_data['id'])->decrement('raffle_num');
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([
+                'id'   => $lucky_id,
+                'name' => $raffledata->name,
+                'img'  => imageToBase64($raffledata->img),
+            ], '抽奖成功,恭喜获得:'.$raffledata->money.'积分');
+        }
+
+//        #[Apidoc\Title("中奖列表")]
+//        #[Apidoc\Url("api/raffle/user_raffle.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+//        #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+//        #[Apidoc\Returned(name: "good_name", type: "int", require: true, desc: '产品名称', default: 10)]
+//        #[Apidoc\Returned(name: "created_at", type: "int", require: true, desc: '中奖时间', default: 10)]
+//        #[Apidoc\Returned(name: "name", type: "int", require: true, desc: '收货人', default: 10)]
+//        #[Apidoc\Returned(name: "mobile", type: "int", require: true, desc: '手机号', default: 10)]
+//        #[Apidoc\Returned(name: "address", type: "int", require: true, desc: '收货地址', default: 10)]
+//        public function userRaffle(Request $request)
+//        {
+//            $param = Arr::only($request->all(), ['page', 'limit']);
+//            try {
+//                Validator::input($param, [
+//                    'page'  => Validator::notEmpty()->intType()->setName('页面'),
+//                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+//                ]);
+//                $data = Db::table('wa_raffle_log')
+//                    ->where('user_id', $request->user_data['id'])
+//                    ->orderByDesc('id')
+//                    ->paginate(Arr::get($param, 'limit', 1))
+//                    ->toArray();
+//                $arr  = [];
+//                foreach ($data['data'] as $k => $v) {
+//                    $raffle = Db::table('wa_raffle')->where('id', $v->raffle_id)->first();
+//                    $arr[]  = [
+//                        'id'         => $v->id,
+//                        'good_name'  => $raffle->name,
+//                        'img'        => getenv('IMG') . $raffle->img,
+//                        'created_at' => date('Y-m-d', strtotime($v->created_at)),
+//                        'name'       => $v->name,
+//                        'mobile'     => $v->mobile,
+//                        'address'    => $v->address
+//                    ];
+//                }
+//            } catch (\Throwable $exception) {
+//                return error($exception->getMessage());
+//            }
+//            return success($arr, '成功', 200, $data['total']);
+//        }
+
+//        #[Apidoc\Title("修改地址")]
+//        #[Apidoc\Url("api/raffle/save_raffle.html")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param("id", type: "int", require: true, desc: "页面", mock: 1)]
+//        #[Apidoc\Param("name", type: "int", require: true, desc: "收货人", mock: 10)]
+//        #[Apidoc\Param("mobile", type: "int", require: true, desc: "手机号", mock: 10)]
+//        #[Apidoc\Param("address", type: "int", require: true, desc: "地址", mock: 10)]
+//        public function save_raffle(Request $request)
+//        {
+//            $param = Arr::only($request->all(), ['id', 'name', 'mobile', 'address']);
+//            try {
+//                Validator::input($param, [
+//                    'id'      => Validator::notEmpty()->setName('非法操作1'),
+//                    'name'    => Validator::notEmpty()->setName('收货人'),
+//                    'mobile'  => Validator::notEmpty()->setName('手机号'),
+//                    'address' => Validator::notEmpty()->setName('收货地址'),
+//                ]);
+//                Db::table('wa_raffle_log')->where('id', $param['id'])->update([
+//                    'name'    => $param['name'],
+//                    'mobile'  => $param['mobile'],
+//                    'address' => $param['address'],
+//                ]);
+//            } catch (\Throwable $exception) {
+//                return error($exception->getMessage());
+//            }
+//            return success();
+//
+//        }
+    }

+ 122 - 0
app/controller/RepaymenController.php

@@ -0,0 +1,122 @@
+<?php
+
+    namespace app\controller;
+
+    use app\business\StreamBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use function Symfony\Component\String\s;
+
+//    #[Apidoc\Title("还款")]
+//    #[Apidoc\Group("User")]
+//    #[Apidoc\Sort(5)]
+    class RepaymenController
+    {
+
+        #[Apidoc\Title("还款")]
+        #[Apidoc\Url("api/repayment.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param(name: "type", type: "string", require: true, desc: '账户类型 1信用卡  2=网络机构', default: '1')]
+        #[Apidoc\Param(name: "account_holder", type: "string", require: true, desc: '姓名', default: '132')]
+        #[Apidoc\Param(name: "money", type: "string", require: true, desc: '还款金额', default: '132')]
+        #[Apidoc\Param(name: "card_number", type: "string", require: true, desc: '卡号', default: '132')]
+        #[Apidoc\Param(name: "affiliated_bank", type: "string", require: true, desc: '所属银行', default: '132')]
+        public function applyfor(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'money' => Validator::notEmpty()->Number()->setName('还款金额'),
+                    'type'  => Validator::notEmpty()->intType()->setName('账户类型'),
+                ]);
+                if ($param['type'] == 1) {
+                    Validator::input($param, [
+                        'account_holder'  => Validator::notEmpty()->setName('持卡人姓名'),
+                        'affiliated_bank' => Validator::notEmpty()->setName('所属银行'),
+                        'card_number'     => Validator::notEmpty()->setName('银行卡号'),
+                    ]);
+                } elseif ($param['type'] == 2) {
+                    Validator::input($param, [
+                        'card_number' => Validator::notEmpty()->setName('微信账号'),
+                    ]);
+                } elseif ($param['type'] == 3) {
+                    Validator::input($param, [
+                        'card_number' => Validator::notEmpty()->setName('支付宝账号'),
+                    ]);
+                } else {
+                    throw new \Exception('非法操作');
+                }
+                $userlist = Db::table('wa_users')->where('id', $param['user_data']['id'])->first();
+                if ($userlist->refund_num <= 0) {
+                    throw new \Exception('还款机会不足!');
+                }
+                $data     = [
+                    'user_id'         => $request->user_data['id'],
+                    'order_no'        => date('YmdHis') . mt_rand(1000, 9999),
+                    'money'           => $param['money'],
+                    'type'            => $param['type'],
+                    'affiliated_bank' => Arr::get($param, 'affiliated_bank'),
+                    'account_holder'  => Arr::get($param, 'account_holder'),
+                    'card_number'     => Arr::get($param, 'card_number'),
+                    'created_at'      => date('Y-m-d H:i:s', time()),
+                    'updated_at'      => date('Y-m-d H:i:s', time()),
+                ];
+                Db::table('wa_repayment')->insert($data);
+                Db::table('wa_users')->where('id', $param['user_data']['id'])->decrement('refund_num', 1);
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+
+            }
+            Db::commit();
+            return success($param, '还款成功');
+
+        }
+
+        #[Apidoc\Title("还款记录")]
+        #[Apidoc\Url("api/repayment/stream.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+        #[Apidoc\Param("limit", type: "int", require: true, desc: "输入条数", mock: 10)]
+        #[Apidoc\Returned(name: "order_no", type: "string", require: true, desc: '订单号', default: '23213213213217182937291')]
+        #[Apidoc\Returned(name: "money", type: "string", require: true, desc: '还款金额', default: '100.00')]
+        #[Apidoc\Returned(name: "status", type: "string", require: true, desc: '提现状态 1 待审核 2打款中 3审核通过 4驳回', default: '1')]
+        #[Apidoc\Returned(name: "type", type: "string", require: true, desc: '账户类型 1信用卡  2=网络机构', default: '1')]
+        #[Apidoc\Returned(name: "account_holder", type: "string", require: true, desc: '开户人', default: '张三')]
+        #[Apidoc\Returned(name: "affiliated_bank", type: "string", require: true, desc: '归属银行', default: '中国银行')]
+        #[Apidoc\Returned(name: "card_number", type: "string", require: true, desc: '卡号|支付宝账号|微信账号', default: '12321321376763274682374681')]
+        #[Apidoc\Returned(name: "created_at", type: "date", require: true, desc: '申请时间', default: '2023-05-20 23:49:49')]
+        public function stream(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            try {
+                Validator::input($param, [
+                    'page'  => Validator::notEmpty()->intType()->setName('页码'),
+                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                ]);
+                $data = Db::table('wa_repayment')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('status', '!=', 0)
+                    ->where(function ($query) use ($param) {
+                        if (Arr::get($param, 'type')) {
+                            $query->where('type', $param['type']);
+                        }
+                    })
+                    ->orderByDesc('id')
+                    ->paginate($param['limit'])->toArray();
+            } catch (\Throwable $exception) {
+                return error($exception->getMessage());
+            }
+            return success($data['data'], '成功', 200, $data['total']);
+        }
+
+    }

+ 71 - 0
app/controller/StreamController.php

@@ -0,0 +1,71 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\LoginBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    #[Apidoc\Title("资金明细")]
+    #[Apidoc\Group("Stream")]
+    #[Apidoc\Sort(5)]
+    class StreamController
+    {
+        #[Apidoc\Title("资金明细")]
+        #[Apidoc\Url("api/stream.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("page", type: "int", desc: "", mock: 1)]
+        #[Apidoc\Param("limit", type: "int", desc: "输出条数", mock: 10)]
+        #[Apidoc\Param("mold", type: "int", require: true, desc: "钱包类型 不传查所有 1 我的资产   2 推荐奖 3 持股数量 4=持股总价值 5=股权分红 ", mock: 1)]
+        public function data(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $param              = Arr::only($request->param_data, ['page', 'limit', 'mold']);
+                $param['user_data'] = $request->user_data;
+                Validator::input($param, [
+                    'page'  => Validator::notEmpty()->intType()->setName('页面'),
+                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                ]);
+                $data = Db::table('wa_stream')->where(function ($query) use ($param) {
+                    $query->where('user_id', $param['user_data']['id']);
+                    if (Arr::get($param, 'mold')) {
+                        $query->where('mold', $param['mold']);
+                    }
+                })->orderByDesc('id')
+                    ->paginate(Arr::get($param,'limit',10),['*'],'page',Arr::get($param,'page'))
+                    ->toArray();
+
+
+                foreach ($data['data'] as $k => $v) {
+                    $data['data'][$k]->type_name = streamType($v->type);
+                    $data['data'][$k]->mold_name = moldType($v->mold);
+                }
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($data);
+
+        }
+
+        #[Apidoc\Title("钱包类型")]
+        #[Apidoc\Url("api/stream/mold_type.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Returned(name: "value", type: "int", require: true, desc: '钱包ID', default: '1')]
+        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '钱包名称', default: '收益余额')]
+        public function moldType(Request $request)
+        {
+            $data = moldType();
+            return success($data);
+        }
+    }

+ 170 - 0
app/controller/UploadController.php

@@ -0,0 +1,170 @@
+<?php
+
+    namespace app\controller;
+
+    use Exception;
+    use Intervention\Image\ImageManagerStatic as Image;
+    use plugin\admin\app\controller\Crud;
+    use plugin\admin\app\model\Upload;
+
+    use support\Db;
+    use support\exception\BusinessException;
+    use support\Request;
+    use support\Response;
+    use hg\apidoc\annotation as Apidoc;
+
+    #[Apidoc\Title("上传")]
+    #[Apidoc\Group("Upload")]
+    #[Apidoc\Sort(1)]
+    class UploadController extends Crud
+    {
+        /**
+         * @var Upload
+         */
+        protected $model = null;
+
+        /**
+         * 只返回当前管理员数据
+         * @var string
+         */
+        protected $dataLimit = 'personal';
+
+        /**
+         * 构造函数
+         * @return void
+         */
+        public function __construct()
+        {
+            $this->model = new Upload;
+        }
+
+        #[Apidoc\Title("上传")]
+        #[Apidoc\Url("api/file")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("file", type: "file", require: true, desc: "上传图片")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '前端展示地址', default: '12317309127904')]
+        public function image(Request $request): Response
+        {
+            $data     = $this->base($request, '/upload/img/' . date('Ymd'));
+            $realpath = $data['realpath'];
+            try {
+                $img        = Image::make($realpath);
+                $max_height = 1170;
+                $max_width  = 1170;
+                $width      = $img->width();
+                $height     = $img->height();
+                $ratio      = 1;
+                if ($height > $max_height || $width > $max_width) {
+                    $ratio = $width > $height ? $max_width / $width : $max_height / $height;
+                }
+                $img->resize($width * $ratio, $height * $ratio)->save($realpath);
+            } catch (Exception $e) {
+                unlink($realpath);
+                return error('处理图片发生错误');
+            }
+
+            /*  Db::table('wa_users')->where('id',$request->user_data['id'])->update(['img'=>$data['url']]);*/
+            return success([
+                'url'  => imageToBase64($data['url']),
+                'path' => $data['url'],
+            ]);
+        }
+
+
+        /**
+         * 获取上传数据
+         * @param Request $request
+         * @param $relative_dir
+         * @return array
+         * @throws BusinessException|RandomException
+         */
+        protected function base(Request $request, $relative_dir): array
+        {
+            $relative_dir = ltrim($relative_dir, '\\/');
+            $file         = current($request->file());
+            if (!$file || !$file->isValid()) {
+                throw new BusinessException('未找到上传文件', 400);
+            }
+
+            $admin_public_path = rtrim(config('app.public_path', ''), '\\/');
+            $base_dir          = $admin_public_path ? $admin_public_path . DIRECTORY_SEPARATOR : base_path() . '/plugin/admin/public/';
+            $full_dir          = $base_dir . $relative_dir;
+            if (!is_dir($full_dir)) {
+                mkdir($full_dir, 0777, true);
+            }
+
+            $ext       = $file->getUploadExtension() ?: null;
+            $mime_type = $file->getUploadMimeType();
+            $file_name = $file->getUploadName();
+            $file_size = $file->getSize();
+
+            if (!$ext && $file_name === 'blob') {
+                [$___image, $ext] = explode('/', $mime_type);
+                unset($___image);
+            }
+
+            $ext               = strtolower($ext);
+            $ext_forbidden_map = ['php', 'php3', 'php5', 'css', 'js', 'html', 'htm', 'asp', 'jsp'];
+            if (in_array($ext, $ext_forbidden_map)) {
+                throw new BusinessException('不支持该格式的文件上传', 400);
+            }
+
+            $relative_path = $relative_dir . '/' . bin2hex(pack('Nn', time(), random_int(1, 65535))) . ".$ext";
+            $full_path     = $base_dir . $relative_path;
+            $file->move($full_path);
+            $image_with = $image_height = 0;
+            if ($img_info = getimagesize($full_path)) {
+                [$image_with, $image_height] = $img_info;
+                $mime_type = $img_info['mime'];
+            }
+            return [
+                'url'          => "/$relative_path",
+                'name'         => $file_name,
+                'realpath'     => $full_path,
+                'size'         => $file_size,
+                'mime_type'    => $mime_type,
+                'image_with'   => $image_with,
+                'image_height' => $image_height,
+                'ext'          => $ext,
+            ];
+        }
+
+
+        #[Apidoc\Title("上传图片base64")]
+        #[Apidoc\Url("api/base_file")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Param("baseimg", type: "string", require: true, desc: "base64编码")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned(name: "url", type: "string", require: true, desc: '前端展示地址', default: '12317309127904')]
+        public function base_file(Request $request): Response
+        {
+            $param              = $request->all();
+            try {
+                $base64Image_one = $param['baseimg'];                                                                                           // 获取Base64字符串
+                $imageData       = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $base64Image_one));                             // 移除数据URL的前缀并解码
+                $imageName       = $request->user_data['id'] . time() . '.png';                                                             // 生成一个唯一的文件名
+
+                $data              = '/upload/img/' . date('Ymd');
+                $relative_dir      = ltrim($data, '\\/');
+                $admin_public_path = rtrim(config('app.public_path', ''), '\\/');
+                $base_dir          = $admin_public_path ? $admin_public_path . DIRECTORY_SEPARATOR : base_path() . '/plugin/admin/public/';
+                $full_dir          = $base_dir . $relative_dir;
+                if (!is_dir($full_dir)) {
+                    mkdir($full_dir, 0777, true);
+                }
+                $imagePath_one = '/upload/img/' . date('Ymd') . '/' . $imageName; // 指定保存路径和文件名
+
+                // 保存图片到服务器
+                file_put_contents($base_dir . $imagePath_one, $imageData);
+            } catch (Exception $e) {
+                return error('处理图片发生错误');
+            }
+            Db::table('wa_users')->where('id',$request->user_data['id'])->update(['sign_img'=>$imagePath_one]);
+            return adminsuccess([
+                'url'  => imageToBase64($imagePath_one),
+                'path' => $imagePath_one,
+            ]);
+        }
+
+    }

+ 461 - 0
app/controller/UserController.php

@@ -0,0 +1,461 @@
+<?php
+
+namespace app\controller;
+
+use app\api\repositories\UsersRepositories;
+use app\business\BankCardBusiness;
+use app\business\LoginBusiness;
+use app\business\StreamBusiness;
+use app\business\UserIdentityBusiness;
+use Illuminate\Support\Arr;
+use Matrix\Exception;
+use Respect\Validation\Validator;
+use support\Db;
+use support\Redis;
+use support\Request;
+use hg\apidoc\annotation as Apidoc;
+use Throwable;
+use Webman\Captcha\CaptchaBuilder;
+use Webman\Captcha\PhraseBuilder;
+use function Symfony\Component\String\s;
+
+#[Apidoc\Title("用户信息")]
+#[Apidoc\Group("User")]
+#[Apidoc\Sort(5)]
+class UserController
+{
+
+    #[Apidoc\Title("用户信息")]
+    #[Apidoc\Url("api/user.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "uuid", type: "int", require: true, desc: 'UUID', default: '100001')]
+    #[Apidoc\Returned(name: "mobile", type: "string", require: true, desc: '账号', default: '15800000000')]
+    #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '主号')]
+    #[Apidoc\Returned(name: "money", type: "string", require: true, desc: '我的资产', default: '0.00')]
+    #[Apidoc\Returned(name: "money_one", type: "string", require: true, desc: '推荐奖', default: '0.00')]
+    #[Apidoc\Returned(name: "money_two", type: "string", require: true, desc: '持股数量', default: '0.00')]
+    #[Apidoc\Returned(name: "money_four", type: "string", require: true, desc: '持股总价值', default: '0.00')]
+    #[Apidoc\Returned(name: "money_five", type: "string", require: true, desc: '股权分红', default: '0.00')]
+    #[Apidoc\Returned(name: "money_six", type: "string", require: true, desc: '股权今日分红', default: '0.00')]
+    #[Apidoc\Returned(name: "money_seven", type: "string", require: true, desc: '总股权分红', default: '0.00')]
+    #[Apidoc\Returned(name: "sign_award", type: "string", require: true, desc: '签到奖励', default: '0.00')]
+    #[Apidoc\Returned(name: "autonym", type: "string", require: true, desc: '实名赠送我的资产', default: '0.00')]
+    #[Apidoc\Returned(name: "invitation_award", type: "string", require: true, desc: '邀请奖励', default: '0.00')]
+    #[Apidoc\Returned(name: "is_alipay", type: "string", require: true, desc: '是否绑定支付宝 true false', default: '0.00')]
+    #[Apidoc\Returned(name: "is_wechat", type: "string", require: true, desc: '是否绑定微信 true false', default: '0.00')]
+    #[Apidoc\Returned(name: "total_sign", type: "int", require: true, desc: '签到总天数', default: '')]
+    #[Apidoc\Returned(name: "day_is_sign", type: "int", require: true, desc: '今日是否签到', default: '')]
+    #[Apidoc\Returned(name: "user_identity", type: "array", desc: '实名信息', default: '', children: [
+        ['name' => "name", 'type' => 'string', 'require' => true, 'default' => '张三1', 'desc' => '姓名'],
+        ['name' => "number", 'type' => 'string', 'require' => true, 'default' => '500221233312836451', 'desc' => '身份证号'],
+    ])]
+    #[Apidoc\Returned(name: "bank_card", type: "string", desc: '银行卡', default: '', children: [
+        ['name' => "affiliated_bank", 'type' => 'string', 'require' => true, 'default' => '中国银行1', 'desc' => '归属银行'],
+        ['name' => "account_holder", 'type' => 'string', 'require' => true, 'default' => '张三', 'desc' => '开户人'],
+        ['name' => "card_number", 'type' => 'string', 'require' => true, 'default' => '500221233312836451', 'desc' => '卡号'],
+    ])]
+    public function userData(Request $request)
+    {
+        //查询今日是否已签到
+        $day_is_sign = Db::table('wa_stream')
+            ->where('type', streamType2)
+            ->whereBetween('add_time', [strtotime(date('Y-m-d')) . ' 00:00:00', strtotime(date('Y-m-d') . ' 23:59:59')])
+            ->where('user_id', $request->user_data['id'])
+            ->first();
+        $total_sign  = Db::table('wa_stream')->where('type', streamType2)->where('user_id', $request->user_data['id'])->count();
+
+        $system = Db::table('wa_system')->first();
+
+        $money_six = Db::table('wa_stream')
+            ->where('type', streamType9)
+            ->where('mold', moldType5)
+            ->whereBetween('add_time', [strtotime(date('Y-m-d')) . ' 00:00:00', strtotime(date('Y-m-d') . ' 23:59:59')])
+            ->where('user_id', $request->user_data['id'])
+            ->sum('money');
+
+//        $is_buy_extract = Db::table('wa_payorder')
+//            ->where('user_id', $request->user_data['id'])
+//            ->where('is_pay', 2)
+//            ->where('goods_type', 4)
+//            ->exists();
+//
+//        $is_alipay = Db::table('wa_binding')
+//            ->where('user_id', $request->user_data['id'])
+//            ->where('type', 1)
+//            ->exists();
+//        $is_weChat = Db::table('wa_binding')
+//            ->where('user_id', $request->user_data['id'])
+//            ->where('type', 2)
+//            ->exists();
+//
+//        $is_buy_sign = Db::table('wa_payorder')
+//            ->where('user_id', $request->user_data['id'])
+//            ->where('is_pay', 2)
+//            ->where('goods_type', 6)
+//            ->exists();
+
+        $is_buy_mail = Db::table('wa_payorder')
+            ->where('user_id', $request->user_data['id'])
+            ->where('is_pay', 2)
+            ->where('goods_type', 9)
+            ->exists();
+
+        $payorderseven = Db::table('wa_payorder')
+            ->where('user_id', $request->user_data['id'])
+            ->where('is_pay', 2)
+            ->where('goods_type', 7)
+            ->first();
+
+        if ($payorderseven) {
+            $is_buy_join = true;
+            $join_name   = $payorderseven->name;
+            $join_number = $payorderseven->number;
+            $join_mobile = $payorderseven->mobile;
+        } else {
+            $is_buy_join = false;
+            $join_name   = '';
+            $join_number = '';
+            $join_mobile = '';
+        }
+
+        $arr = [
+            'img'              => !empty($request->user_data['img']) ? imageToBase64($request->user_data['img']) : '',
+            'uuid'             => $request->user_data['uuid'],
+            'mobile'           => $request->user_data['mobile'],
+            'name'             => $request->user_data['name'],
+            'is_autonym'       => $request->user_data['is_autonym'],
+            'is_num'           => $request->user_data['is_num'],
+            'money'            => $request->user_data['money'],
+            'money_one'        => $request->user_data['money_one'],
+            'money_two'        => $request->user_data['money_two'],
+            'money_four'       => $request->user_data['money_four'],
+            'money_five'       => $request->user_data['money_five'],
+            'pass_one'         => $request->user_data['pass_one'],
+            'sign_img'         => !empty($request->user_data['sign_img']) ? imageToBase64($request->user_data['sign_img']) : '',
+            'sign_time'        => $request->user_data['sign_time'],
+            'money_six'        => $money_six,
+            'money_seven'      => $request->user_data['money_seven'],
+            'mail_province'    => $request->user_data['mail_province'],
+            'mail_address'     => $request->user_data['mail_address'],
+            'sign_award'       => $system->sign_award,
+            'autonym'          => $system->autonym,
+            'invitation_award' => $system->invitation_award,
+            'rebate'           => $system->rebate,
+            //            'day_is_sign'      => $day_is_sign ? true : false,
+            //            'is_wechat'        => $is_weChat ? true : false,
+            //            'is_alipay'        => $is_alipay ? true : false,
+            //            'is_buy_extract'   => $is_buy_extract ? true : false,
+            //            'is_buy_sign'      => $is_buy_sign ? true : false,
+            'is_buy_mail'      => $is_buy_mail ? true : false,
+            'day_is_sign'      => true,
+            'is_wechat'        => true,
+            'is_alipay'        => true,
+            'is_buy_extract'   => true,
+            'is_buy_sign'      => true,
+            'is_buy_join'      => $is_buy_join,
+            'total_sign'       => $total_sign,
+            'user_identity'    => UserIdentityBusiness::data(['uid' => $request->user_data['id']]),
+            'bank_card'        => BankCardBusiness::data(['uid' => $request->user_data['id']]),
+            'wechat_binding'   => $request->user_data['wechat_binding'],
+            'alipay_binding'   => $request->user_data['alipay_binding'],
+            'join_name'        => $join_name,
+            'join_number'      => $join_number,
+            'join_mobile'      => $join_mobile,
+
+        ];
+        return success($arr);
+    }
+
+    #[Apidoc\Title("签到列表")]
+    #[Apidoc\Url("api/user/signlist.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "money", type: "string", desc: '签到奖励', default: '')]
+    #[Apidoc\Returned(name: "day", type: "string", desc: '天数', default: '')]
+    #[Apidoc\Returned(name: "has", type: "string", desc: '是否签到', default: 'true  已签到  false 未签到')]
+    #[Apidoc\Returned(name: "signcount", type: "string", desc: '累计签到天数', default: '1')]
+    #[Apidoc\Returned(name: "continuity", type: "string", desc: '连续签到天数', default: 't1')]
+    #[Apidoc\Returned(name: "is_sign", type: "string", desc: '今日是否签到', default: 'true  已签到  false 未签到')]
+    public function signlist(Request $request)
+    {
+        $system = Db::table('wa_system')->first();
+        $arr[]  = date('Y-m-d', strtotime('monday this week'));
+        $arr[]  = date('Y-m-d', strtotime('monday this week +1 day'));
+        $arr[]  = date('Y-m-d', strtotime('monday this week +2 day'));
+        $arr[]  = date('Y-m-d', strtotime('monday this week +3 day'));
+        $arr[]  = date('Y-m-d', strtotime('monday this week +4 day'));
+        $arr[]  = date('Y-m-d', strtotime('monday this week +5 day'));
+        $arr[]  = date('Y-m-d', strtotime('sunday this week'));
+        $array  = [];
+        foreach ($arr as $k => $v) {
+            $array[] = [
+                'day' => date('d', strtotime($v)),
+                'has' => Db::table('wa_stream')
+                    ->where('user_id', $request->user_data['id'])
+                    ->where('type', streamType2)
+                    ->whereBetween('add_time', [strtotime($v . ' 00:00:00'), strtotime($v . ' 23:59:59')])->exists()
+            ];
+        }
+        $signcount = Db::table('wa_stream')->where('type', streamType2)->where('user_id', $request->user_data['id'])->count();
+        $is_sign   = Db::table('wa_stream')
+            ->where('user_id', $request->user_data['id'])
+            ->where('type', streamType2)
+            ->whereBetween('add_time', [strtotime(date('Y-m-d') . ' 00:00:00'), strtotime(date('Y-m-d') . ' 23:59:59')])
+            ->exists();
+        return success([
+            'list'       => $array,
+            'signcount'  => $signcount,
+            'continuity' => $request->user_data['continuity'],
+            'money'      => $system->sign_award,
+            'is_sign'    => $is_sign,
+        ]);
+
+    }
+
+    #[Apidoc\Title("签到")]
+    #[Apidoc\Url("api/user/sign.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "money", type: "string", desc: '奖励金额', default: '888')]
+    #[Apidoc\Returned(name: "signcount", type: "string", desc: '累计签到天数', default: '888')]
+    public function sign(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $zuotian = Db::table('wa_stream')
+                ->where('user_id', $request->user_data['id'])
+                ->where('type', streamType2)
+                ->whereBetween('add_time', [bcsub(strtotime(date('Y-m-d') . ' 00:00:00'), 86400), bcadd(strtotime(date('Y-m-d') . ' 23:59:59'), 86400)])
+                ->exists();
+            if ($zuotian) {
+                $continuity = bcadd($request->user_data['continuity'], 1);
+            } else {
+                $continuity = 1;
+            }
+
+            $has = Db::table('wa_stream')
+                ->where('user_id', $request->user_data['id'])
+                ->where('type', streamType2)
+                ->whereBetween('add_time', [strtotime(date('Y-m-d') . ' 00:00:00'), strtotime(date('Y-m-d') . ' 23:59:59')])
+                ->exists();
+            if ($has) {
+                throw new \Exception('今日已签到,请不要重复签到');
+            }
+
+            $system = Db::table('wa_system')->first();
+
+            if (!empty($system->sign_award)) {
+                StreamBusiness::addStream($request->user_data['id'], $system->sign_award, streamType2, moldType1, moldTypefild1);
+            }
+            $signcount = Db::table('wa_stream')->where('type', streamType2)->where('user_id', $request->user_data['id'])->count();
+            Db::table('wa_users')->where(['id' => $request->user_data['id']])->update(['continuity' => $continuity]);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([
+            'money'     => $system->sign_award,
+            'signcount' => $signcount
+        ], '签到成功');
+    }
+
+    #[Apidoc\Title("我的团队头数据")]
+    #[Apidoc\Url("api/user/team.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "num", type: "int", require: true, desc: '团队总人数', default: '1')]
+    #[Apidoc\Returned(name: "day_num", type: "int", require: true, desc: '今日新增人数', default: '1')]
+    #[Apidoc\Returned(name: "earnings", type: "int", require: true, desc: '总拥金收益', default: '0')]
+    #[Apidoc\Returned(name: "dayearnings", type: "int", require: true, desc: '今日收益', default: '0')]
+    #[Apidoc\Returned(name: "money", type: "int", require: true, desc: '总业绩', default: '0')]
+    #[Apidoc\Returned(name: "one", type: "int", require: true, desc: '一级人数', default: '0')]
+    #[Apidoc\Returned(name: "two", type: "int", require: true, desc: '二级人数', default: '0')]
+    #[Apidoc\Returned(name: "three", type: "int", require: true, desc: '三级人数', default: '0')]
+    #[Apidoc\Returned(name: "rebate", type: "int", require: true, desc: '一级返佣', default: '0')]
+    #[Apidoc\Returned(name: "rebate_one", type: "int", require: true, desc: '二级返佣', default: '0')]
+    #[Apidoc\Returned(name: "rebate_two", type: "int", require: true, desc: '三级返佣', default: '0')]
+    public function team(Request $request)
+    {
+        $param = $request->user_data;
+
+        $data   = Db::table('wa_users')->where(function ($query) use ($param) {
+            $query->orWhere('pid', $param['id']);
+            $query->orWhere('ppid', $param['id']);
+            $query->orWhere('toppid', $param['id']);
+        });
+        $system = Db::table('wa_system')->first();
+        /** @var  $num  团队总人数 */
+        $num    = (clone $data)->count();
+        $stream = Db::table('wa_stream')->where('mold', moldType2)->where('user_id', $request->user_data['id']);
+        return success([
+            'num'         => $num,
+            'day_num'     => (clone $data)
+                ->where('created_at', '>=', date('Y-m-d') . ' 00:00:00')
+                ->where('created_at', '<=', date('Y-m-d') . ' 23:59:59')->count(),
+            'earnings'    => (clone $stream)->sum('money'),
+            'dayearnings' => (clone $stream)
+                ->where('add_time', '>=', strtotime(date('Y-m-d')))
+                ->where('add_time', '<=', strtotime(date('Y-m-d 23:59:59')))
+                ->sum('money'),
+            'money'       => (clone $data)->sum('invest_money'),
+            'one'         => Db::table('wa_users')->where('pid', $param['id'])->count(),
+            'two'         => Db::table('wa_users')->where('ppid', $param['id'])->count(),
+            'three'       => Db::table('wa_users')->where('toppid', $param['id'])->count(),
+            'rebate'      => $system->rebate,
+            'rebate_one'  => $system->rebate_one,
+            'rebate_two'  => $system->rebate_two,
+        ]);
+
+    }
+
+    #[Apidoc\Title("我的团队列表数据")]
+    #[Apidoc\Url("api/user/team_list.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+    #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+    #[Apidoc\Param("grade", type: "int", require: true, desc: "等级 1一级 2二级 3三级", mock: 1)]
+    #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '名称', default: '未实名')]
+    #[Apidoc\Returned(name: "mobile", type: "string", require: true, desc: '电话', default: '158****0002')]
+    #[Apidoc\Returned(name: "join_time", type: "string", require: true, desc: '注册时间', default: '2024-07-08 01:20:47')]
+    #[Apidoc\Returned(name: "invest_money", type: "string", require: true, desc: '消费金额', default: '0.00')]
+    public function teamList(Request $request)
+    {
+        try {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Validator::input($param, [
+                'page'  => Validator::notEmpty()->intType()->setName('页面'),
+                'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                'grade' => Validator::notEmpty()->intType()->setName('等级'),
+            ]);
+            $data = Db::table('wa_users')->where(function ($query) use ($param) {
+                if (Arr::get($param, 'grade')) {
+                    if ($param['grade'] == 1) {
+                        $query->where('pid', $param['user_data']['id']);
+                    } elseif ($param['grade'] == 2) {
+                        $query->where('ppid', $param['user_data']['id']);
+                    } elseif ($param['grade'] == 3) {
+                        $query->where('toppid', $param['user_data']['id']);
+                    }
+                } else {
+                    $query->where('pid', $param['user_data']['id']);
+                }
+            })->select(['name', 'mobile', 'join_time', 'invest_money'])
+                ->orderByDesc('id')
+                ->paginate(Arr::get($param, 'limit', 10))
+                ->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]->mobile = substr_replace($v->mobile, '****', 3, 4);
+            }
+
+        } catch (\Throwable $exception) {
+            return new Exception($exception->getMessage());
+        }
+
+        return success($data['data'], '成功', 200, $data['total']);
+    }
+
+//        #[Apidoc\Title("我的投资")]
+//        #[Apidoc\Url("api/user/mygoods")]
+//        #[Apidoc\Method("POST")]
+//        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+//        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+//        #[Apidoc\Param("limit", type: "int", require: true, desc: "输出条数", mock: 10)]
+//        #[Apidoc\Returned(name: "id", type: "string", require: true, desc: '购买记录ID', default: '485')]
+//        #[Apidoc\Returned(name: "goods_id", type: "string", require: true, desc: '产品ID', default: '5')]
+//        #[Apidoc\Returned(name: "img", type: "string", require: true, desc: '封面图', default: '')]
+//        #[Apidoc\Returned(name: "name", type: "string", require: true, desc: '产品名称', default: '')]
+//        #[Apidoc\Returned(name: "type", type: "string", require: true, desc: '产品类型 1 慈善 2助力', default: '')]
+//        #[Apidoc\Returned(name: "price", type: "string", require: true, desc: '价格', default: '')]
+//        #[Apidoc\Returned(name: "pay_price", type: "string", require: true, desc: '通道支付金额', default: '')]
+//        #[Apidoc\Returned(name: "period", type: "string", require: true, desc: '周期', default: '')]
+//        #[Apidoc\Returned(name: "bl", type: "string", require: true, desc: '比例', default: '')]
+//        #[Apidoc\Returned(name: "bonus", type: "string", require: true, desc: '每日分红金额', default: '')]
+//        #[Apidoc\Returned(name: "predict", type: "string", require: true, desc: '预计收益', default: '')]
+//        #[Apidoc\Returned(name: "created_at", type: "string", require: true, desc: '购买时间', default: '')]
+//        #[Apidoc\Returned(name: "expiretime", type: "string", require: true, desc: '到期时间戳', default: '')]
+//        #[Apidoc\Returned(name: "is_grant", type: "string", require: true, desc: '是否退本 1未退本  2已退本', default: '')]
+//        public function mygoods(Request $request)
+//        {
+//            try {
+//                $param              = Arr::only($request->all(), ['page', 'limit', 'grade']);
+//                $param['user_data'] = $request->user_data;
+//                Validator::input($param, [
+//                    'page'  => Validator::notEmpty()->intType()->setName('页码'),
+//                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+//                ]);
+//                $data = Db::table('wa_my_goods')
+//                    ->join('wa_goods', 'wa_goods.id', '=', 'wa_my_goods.goods_id')
+//                    ->where('wa_my_goods.user_id', $param['user_data']['id'])
+//                    ->select(['wa_my_goods.id', 'wa_my_goods.goods_id', 'wa_goods.img', 'wa_goods.type', 'wa_goods.pay_price', 'wa_goods.price', 'wa_goods.name', 'wa_goods.period', 'wa_goods.bl', 'wa_goods.bonus', 'wa_goods.predict', 'wa_goods.bonus', 'wa_my_goods.created_at', 'wa_my_goods.expiretime', 'wa_my_goods.is_grant'])
+//                    ->orderByDesc('wa_my_goods.id')
+//                    ->paginate(Arr::get($param, 'limit', 10))
+//                    ->toArray();
+//                foreach ($data['data'] as $k => $v) {
+//                    $data['data'][$k]->img = getenv('IMG') . $v->img;
+//                }
+//            } catch (\Throwable $exception) {
+//                return error($exception->getMessage());
+//            }
+//
+//            return success($data['data'], '成功', 200, $data['total']);
+//        }
+
+    #[Apidoc\Title("退出登录")]
+    #[Apidoc\Url("api/user/quit.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    public function quit(Request $request)
+    {
+        Redis::del($request->user_data['id']);
+        return success([], '已退出登录!');
+    }
+
+    #[Apidoc\Title("修改密码")]
+    #[Apidoc\Url("api/user/save.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Param("type", type: "int", require: true, desc: "类型 1修改名称  2 修改密码 ", mock: 1)]
+    #[Apidoc\Param("name", type: "string", require: true, desc: "名称", mock: 1)]
+    #[Apidoc\Param("old_password", type: "string", require: true, desc: "旧密码", mock: 1)]
+    #[Apidoc\Param("password", type: "string", require: true, desc: "新密码", mock: 10)]
+    public function save(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param = $request->param_data;
+            Validator::input($param, [
+                'type' => Validator::notEmpty()->intType()->setName('操作类型'),
+            ]);
+            if (Arr::get($param, 'type') == 1) {
+                Validator::input($param, [
+                    'name' => Validator::notEmpty()->setName('操作类型'),
+                ]);
+                $arr['name'] = $param['name'];
+
+            } elseif (Arr::get($param, 'type') == 2) {
+                Validator::input($param, [
+                    'old_password' => Validator::notEmpty()->setName('旧密码'),
+                    'password'     => Validator::notEmpty()->setName('新密码'),
+                ]);
+                if ($request->user_data['password'] != md5($param['old_password'])) {
+                    throw new \Exception('密码验证失败');
+                }
+                $arr['password'] = md5($param['password']);
+            }
+            if (empty($arr)) {
+                throw new \Exception('非法操作');
+            }
+            Db::table('wa_users')->where('id', $request->user_data['id'])->update($arr);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '修改成功');
+    }
+
+}

+ 53 - 0
app/controller/UserIdentityController.php

@@ -0,0 +1,53 @@
+<?php
+
+    namespace app\controller;
+
+    use app\api\repositories\UsersRepositories;
+    use app\business\BankCardBusiness;
+    use app\business\LoginBusiness;
+    use app\business\UserIdentityBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    #[Apidoc\Title("实名认证+修改实名信息")]
+    #[Apidoc\Group("UserIdentity")]
+    #[Apidoc\Sort(5)]
+    class UserIdentityController
+    {
+
+        #[Apidoc\Title("实名认证+修改实名信息")]
+        #[Apidoc\Url("api/user/identity.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("name", type: "string", require: true, desc: "姓名", mock: "张三")]
+        #[Apidoc\Param("number", type: "string", require: true, desc: "身份证号码 16-18位", mock: 500221233312836451)]
+        public function Updata(Request $request)
+        {
+            $param              = $request->param_data;
+            $param              = Arr::only($param, ['name', 'number']);
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'name'   => Validator::notEmpty()->stringType()->setName('姓名'),
+                    'number' => Validator::notEmpty()->stringType()->Length(16, 18)->setName('身份证号码'),
+                ]);
+                UserIdentityBusiness::UpData($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success();
+
+
+        }
+
+
+    }

+ 97 - 0
app/controller/WithdrawController.php

@@ -0,0 +1,97 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\GoodsBusiness;
+    use app\business\LoginBusiness;
+    use app\business\PayorderBusiness;
+    use app\business\WithdrawBusiness;
+    use Illuminate\Support\Arr;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Redis;
+    use support\Request;
+    use hg\apidoc\annotation as Apidoc;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    #[Apidoc\Title("提现")]
+    #[Apidoc\Group("Stream")]
+    #[Apidoc\Sort(5)]
+    class WithdrawController
+    {
+        #[Apidoc\Title("提现申请")]
+        #[Apidoc\Url("api/withdraw.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("money", type: "int", require: true, desc: "提现金额", mock: 10)]
+        #[Apidoc\Param("mold", type: "int", require: true, desc: "钱包类型 ", mock: 1)]
+        #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+        #[Apidoc\Param(name: "binding_type", type: "int", require: true, desc: '我的资产转入:1=支付宝,2=微信', default: '1')]
+        public function applyfor(Request $request)
+        {
+            $param              = Arr::only($request->param_data,['money','mold','binding_type']);
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'money' => Validator::notEmpty()->Number()->setName('提现金额'),
+                    'mold'  => Validator::notEmpty()->intType()->setName('钱包类型'),
+                ]);
+                $name = Db::table('wa_user_identity')->where('uid', $request->user_data['id'])->value('name');
+                if (empty($name)) {
+                    throw new \Exception('请实名后再进行提现!');
+                }
+                $account_holder = Db::table('wa_bank_card')->where('uid', $request->user_data['id'])->value('account_holder');
+                if (empty($account_holder)) {
+                    throw new \Exception('请绑定银行卡!');
+                }
+                if ($account_holder != $name) {
+                    throw new \Exception('实名人和开户人不一致,请绑定实名人的银行卡!');
+                }
+                $arr = WithdrawBusiness::applyfor($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($arr, '提现成功');
+
+        }
+
+        #[Apidoc\Title("提现记录")]
+        #[Apidoc\Url("api/withdraw/stream.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("page", type: "int", require: true, desc: "页面", mock: 1)]
+        #[Apidoc\Param("limit", type: "int", require: true, desc: "输入条数", mock: 10)]
+        #[Apidoc\Param("mold", type: "int", require: true, desc: "钱包类型   ", mock: 1)]
+        #[Apidoc\Param("type", type: "int", require: true, desc: "钱包类型 1=转入记录(全部),2=支付宝转入,3=微信转入,4=提现记录  ", mock: 1)]
+        #[Apidoc\Returned(name: "order_no", type: "string", require: true, desc: '订单号', default: '23213213213217182937291')]
+        #[Apidoc\Returned(name: "money", type: "string", require: true, desc: '提现金额', default: '100.00')]
+        #[Apidoc\Returned(name: "status", type: "string", require: true, desc: '提现状态 1 待审核 2打款中 3审核通过(成功,通过) 4驳回(失败)', default: '1')]
+        #[Apidoc\Returned(name: "binding_type", type: "string", require: true, desc: '1=转入支付宝,2=转入微信', default: '1')]
+        #[Apidoc\Returned(name: "affiliated_bank", type: "string", require: true, desc: '归属银行', default: '中国银行')]
+        #[Apidoc\Returned(name: "account_holder", type: "string", require: true, desc: '开户人', default: '张三')]
+        #[Apidoc\Returned(name: "card_number", type: "string", require: true, desc: '卡号', default: '12321321376763274682374681')]
+        #[Apidoc\Returned(name: "created_at", type: "date", require: true, desc: '申请时间', default: '2023-05-20 23:49:49')]
+        public function stream(Request $request)
+        {
+            $param              = $request->param_data;
+            $param              = Arr::only($param, ['page', 'limit', 'mold']);
+            $param['user_data'] = $request->user_data;
+            try {
+                Validator::input($param, [
+                    'page'  => Validator::notEmpty()->intType()->setName('页码'),
+                    'limit' => Validator::notEmpty()->intType()->setName('输出条数'),
+                ]);
+                $data = WithdrawBusiness::stream($param);
+            } catch (\Throwable $exception) {
+                return error($exception->getMessage());
+            }
+            return success($data['data'], '成功', 200, $data['total']);
+        }
+
+
+    }

+ 419 - 0
app/functions.php

@@ -0,0 +1,419 @@
+<?php
+    /**
+     * Here is your custom functions.
+     */
+
+    use Firebase\JWT\JWT;
+    use Firebase\JWT\Key;
+
+    /* @登录失效码*/
+    define('USER_INVALID', 4008);
+    /* @无权限码*/
+    define('USER_AUTH', 4009);
+    /* @错误码*/
+    define('ERROR', 400);
+    /* @成功码*/
+    define('SUCCESS', 0);
+
+
+    function error($msg = '请求成功', $data = [], $code = ERROR)
+    {
+        $result = [
+            'code'    => $code,
+            'message' => $msg,
+            'time'    => time(),
+            'data'    => $data,
+        ];
+        $result = encrypt($result);
+        return json($result);
+    }
+    function adminerror($msg = '请求成功', $data = [], $code = ERROR)
+    {
+        $result = [
+            'code'    => $code,
+            'message' => $msg,
+            'time'    => time(),
+            'data'    => $data,
+        ];
+        return json($result);
+    }
+
+
+    function success($data = [], $msg = '请求成功', $code = 200, $count = 0)
+    {
+        $result = [
+            'code'    => $code,
+            'message' => $msg,
+            'data'    => $data,
+            'count'   => $count
+        ];
+        $result = encrypt($result);
+        return json($result);
+    }
+
+    function adminsuccess($data = [], $msg = '请求成功', $code = 200, $count = 0)
+    {
+        $result = [
+            'code'    => $code,
+            'message' => $msg,
+            'data'    => $data,
+            'count'   => $count
+        ];
+        return json($result);
+    }
+
+    /** 加密
+     * @param $data
+     * @return void
+     */
+    function jwtEncode($data)
+    {
+        return JWT::encode($data, getenv('JWT_PRIVATEKEY'), 'HS256');
+    }
+
+    /** 解密
+     * @param $data
+     * @return void
+     */
+    function jwtDecode($data)
+    {
+        try {
+            $data = JWT::decode($data, new Key(getenv('JWT_PRIVATEKEY'), 'HS256'));
+        } catch (\Exception $exception) {
+            throw new \Exception('验证失败');
+        }
+        return $data;
+    }
+
+    /** 钱包名称
+     * @param $value
+     * @return array[]|mixed
+     */
+    function moldType($value = '')
+    {
+        $arr = [
+            [
+                'value' => 1,
+                'name'  => '我的资产',
+            ], [
+                'value' => 2,
+                'name'  => '推荐奖',
+            ], [
+                'value' => 3,
+                'name'  => '持股数量',
+            ],
+            [
+                'value' => 4,
+                'name'  => '持股总价值',
+            ]
+            , [
+                'value' => 5,
+                'name'  => '股权分红',
+            ]
+        ];
+        if ($value) {
+            $data = collect($arr)->where('value', $value)->first();
+            return $data['name'];
+        } else {
+            return $arr;
+        }
+    }
+
+    /**  产品类型
+     * @param $type
+     * @return string
+     */
+    function cardNumberType($type = '')
+    {
+        if ($type == 1) {
+            return '股权产品';
+        } else {
+            return '无';
+        }
+    }
+
+
+    /**钱包字段
+     * @param $value
+     * @return array[]|mixed
+     */
+//我的资产
+    define('moldType1', 1);
+    define('moldTypefild1', 'money');
+//推荐奖
+    define('moldType2', 2);
+    define('moldTypefild2', 'money_one');
+//持股数量
+    define('moldType3', 3);
+    define('moldTypefild3', 'money_two');
+//持股总价值
+    define('moldType4', 4);
+    define('moldTypefild4', 'money_four');
+//股权分红
+    define('moldType5', 5);
+    define('moldTypefild5', 'money_five');
+
+
+    function moldTypefild($value = '')
+    {
+        $arr = [
+            [
+                'value' => 1,
+                'name'  => 'money',
+            ], [
+                'value' => 2,
+                'name'  => 'money_one',
+            ], [
+                'value' => 3,
+                'name'  => 'money_two',
+            ],
+            [
+                'value' => 4,
+                'name'  => 'money_four',
+            ],
+            [
+                'value' => 5,
+                'name'  => 'money_five',
+            ]
+        ];
+        if ($value) {
+            $data = collect($arr)->where('value', $value)->first();
+            return $data['name'];
+        } else {
+            return $arr;
+        }
+    }
+
+    /** 流水类型 */
+    /** 注册奖励 */
+    define('streamType1', 1);
+    /** 签到 */
+    define('streamType2', 2);
+    /**  邀请*/
+    define('streamType3', 3);
+    /** 提现 */
+    define('streamType4', 4);
+    /** 购买 */
+    define('streamType5', 5);
+    /** 提现驳回 */
+    define('streamType6', 6);
+    /** 平台充值 */
+    define('streamType7', 7);
+    /** 平台扣款 */
+    define('streamType8', 8);
+    /** 产品分红 */
+    define('streamType9', 9);
+    /** 产品分佣 */
+    define('streamType10', 10);
+    /** 实名奖励 */
+    define('streamType11', 11);
+
+    /** 抽奖 */
+    define('streamType12', 12);
+    /** 数据恢复 */
+    define('streamType13', 13);
+
+    /** 转账 */
+    define('streamType14', 14);
+    /** 产品赠送 */
+    define('streamType15', 15);
+    /** 兑换 */
+    define('streamType16', 16);
+    /** 出售股权 */
+    define('streamType17', 17);
+
+    function streamType($value = '')
+    {
+        $arr = [
+            [
+                'value' => 1,
+                'name'  => '注册奖励',
+            ],
+            [
+                'value' => 2,
+                'name'  => '签到',
+            ],
+            [
+                'value' => 3,
+                'name'  => '邀请',
+            ],
+            [
+                'value' => 4,
+                'name'  => '提现',
+            ],
+            [
+                'value' => 5,
+                'name'  => '购买',
+            ],
+            [
+                'value' => 6,
+                'name'  => '提现驳回',
+            ],
+            [
+                'value' => 7,
+                'name'  => '平台充值',
+            ],
+            [
+                'value' => 8,
+                'name'  => '平台扣款',
+            ],
+            [
+                'value' => 9,
+                'name'  => '产品结息',
+            ],
+            [
+                'value' => 10,
+                'name'  => '产品分佣',
+            ],
+            [
+                'value' => 11,
+                'name'  => '实名奖励',
+            ],
+            [
+                'value' => 12,
+                'name'  => '抽奖获得',
+            ],
+            [
+                'value' => 13,
+                'name'  => '数据恢复',
+            ],
+            [
+                'value' => 14,
+                'name'  => '转账',
+            ],
+            [
+                'value' => 15,
+                'name'  => '产品赠送',
+            ],
+            [
+                'value' => 16,
+                'name'  => '兑换',
+            ],
+            [
+                'value' => 17,
+                'name'  => '出售股权',
+            ]
+        ];
+        if ($value) {
+            $data = collect($arr)->where('value', $value)->first();
+            return $data['name'];
+        } else {
+            return $arr;
+        }
+    }
+
+    /** 获取未来时间 */
+    function futureDay($day)
+    {
+        return date('Y-m-d', strtotime("+$day days")) . ' 23:59:59';
+    }
+
+    /** 后台登录名称 */
+    function adminName()
+    {
+        return md5(getenv('PROJECT') . date('Ymd'));
+    }
+
+
+    function imgtxt($html)
+    {
+        if (empty($html)) {
+            return $html;
+        }
+// 要替换的目标字符串
+        $target = getenv('IMG');
+// 正则表达式匹配所有<img>标签
+        $pattern = '/<img[^>]+/i';
+// 正则表达式匹配src属性
+        $src_pattern = '/src="([^"]+)/i';
+
+// 执行替换
+        $replaced_html = preg_replace_callback($pattern, function ($matches) use ($src_pattern, $target) {
+            // 匹配src属性
+            preg_match($src_pattern, $matches[0], $src_matches);
+            // 如果找到了src属性,则替换它
+            if (isset($src_matches[1])) {
+                // 构造新的<img>标签
+
+                if (strpos($src_matches[1], 'http') !== false) {
+
+                } else {
+                    return str_replace($src_matches[1], imageToBase64($src_matches[1]), $matches[0]);
+                }
+
+            }
+            // 如果没有找到src属性,直接返回原始<img>标签
+            return $matches[0];
+        }, $html);
+
+// 输出替换后的HTML内容
+        return $replaced_html;
+    }
+
+    function uuid()
+    {
+        $uuid = \support\Db::table('wa_users')->orderByDesc('uuid')->value('uuid');
+        return bcadd($uuid, bcadd(mt_rand(100, 999), date('d')));
+    }
+
+
+    /**
+     * 生成银行卡号
+     * @param $length
+     * @return string
+     */
+    function generateBankAccountNumber($length = 19)
+    {
+        $prefix       = '6221';                                                              // 定义账号前缀,如银行标识
+        $suffixLength = $length - strlen($prefix);                                           // 计算后缀的长度
+        $suffix       = substr(mt_rand(100000000000000, 999999999999999), 0, $suffixLength); // 随机生成后缀
+        return $prefix . $suffix;
+    }
+
+    /**
+     * 生成证 书编号
+     * @return string
+     * @throws \Random\RandomException
+     */
+    function generateCertificateNumber($length = 12)
+    {
+        $prefix       = 'JZYH';                                                              // 定义账号前缀,如银行标识
+        $suffixLength = $length - strlen($prefix);                                           // 计算后缀的长度
+        $suffix       = substr(mt_rand(100000000000000, 999999999999999), 0, $suffixLength); // 随机生成后缀
+        return $prefix . $suffix;
+    }
+
+    /**
+     * 生成随机字母
+     * @param $length
+     * @return string
+     */
+    function RandomAlphaNum($length = 4)
+    {
+        $randomString = '';
+        for ($i = 0; $i < $length; $i ++) {
+            $randomString .= chr(rand(65, 90)); // 生成大写字母 'A' 到 'Z'
+            // 如果需要包含小写字母,取消下面这行的注释
+            // $randomString .= chr(rand(97, 122)); // 生成小写字母 'a' 到 'z'
+        }
+        return $randomString;
+    }
+
+    function encrypt($data)
+    {
+        $info = openssl_encrypt (json_encode ($data, JSON_UNESCAPED_UNICODE), 'AES-128-ECB', getenv ("JWT_AESKEY"), OPENSSL_RAW_DATA) ;
+        return base64_encode ($info);
+    }
+
+    function imageToBase64($imagePath)
+    {
+        if (file_exists('./public'.$imagePath) && !empty($imagePath)) {
+//            $image  = file_get_contents('./public'.$imagePath);
+//            $base64 = base64_encode($image);
+//            return 'data:image/jpeg;base64,' . $base64; // 这里假设图片为JPEG格式,根据实际需要修改
+            return getenv('IMG').$imagePath;
+        } else {
+            return '';
+        }
+
+    }

+ 71 - 0
app/middleware/Decrypt.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace app\middleware;
+
+use Illuminate\Support\Arr;
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+/**
+ * Class StaticFile
+ * @package app\middleware
+ */
+class Decrypt implements MiddlewareInterface
+{
+    public function process(Request $request, callable $handler): Response
+    {
+        $transfersecret=$request->header('transfersecret');
+        if(empty($transfersecret)){
+            return $this->transfer();
+        }
+        $string_data = openssl_decrypt(base64_decode($transfersecret),'AES-128-ECB',getenv ("JWT_AESKEY"),OPENSSL_RAW_DATA);
+        if(!$string_data){
+            return $this->transfer();
+        }
+        $param_data = json_decode($string_data,true);
+        if(!$param_data){
+            return $this->transfer();
+        }
+        $request->param_data=$param_data;
+        /** @var Response $response */
+        return $handler($request);
+    }
+
+    public function transfer()
+    {
+        $arr=[
+            0=>'https://www.baidu.com',
+            1=>'https://weibo.com',
+            2=>'https://www.douyin.com',
+            3=>'https://www.jd.com',
+            4=>'https://uland.taobao.com',
+            5=>'https://news.qq.com',
+            6=>'https://www.toutiao.com',
+            7=>'https://www.kuaishou.com',
+            8=>'https://www.sohu.com',
+        ];
+        return redirect($arr[mt_rand(0,8)]);
+    }
+    public function sign($array)
+    {
+        ksort($array);                               //ASCII码排序
+        $md5str = "";
+        foreach ($array as $key => $val) {
+            $md5str = $md5str . $key . "=" . $val . "&";
+        }
+        return md5($md5str . "key=".getenv('JWT_PRIVATEKEY'));
+    }
+}

+ 83 - 0
app/middleware/Sign.php

@@ -0,0 +1,83 @@
+<?php
+    /**
+     * This file is part of webman.
+     *
+     * Licensed under The MIT License
+     * For full copyright and license information, please see the MIT-LICENSE.txt
+     * Redistributions of files must retain the above copyright notice.
+     *
+     * @author    walkor<walkor@workerman.net>
+     * @copyright walkor<walkor@workerman.net>
+     * @link      http://www.workerman.net/
+     * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+     */
+
+    namespace app\middleware;
+
+    use Illuminate\Support\Arr;
+    use Webman\MiddlewareInterface;
+    use Webman\Http\Response;
+    use Webman\Http\Request;
+
+    /**
+     * Class StaticFile
+     * @package app\middleware
+     */
+    class Sign implements MiddlewareInterface
+    {
+        public function process(Request $request, callable $next): Response
+        {
+            $sign = $request->header('sign');
+            if (empty($sign)) {
+                return $this->transfer();
+            }
+            $transfersecret=$request->header('transfersecret');
+            if(empty($transfersecret)){
+                return $this->transfer();
+            }
+            $string_data = openssl_decrypt(base64_decode($transfersecret),'AES-128-ECB',getenv ("JWT_AESKEY"),OPENSSL_RAW_DATA);
+            if(!$string_data){
+                return $this->transfer();
+            }
+            $param_data = json_decode($string_data,true);
+            if(!$param_data){
+                return $this->transfer();
+            }
+            $param = $param_data;
+            if (Arr::get($param, 'time', 0) < (time() - 15)) {
+                return $this->transfer();
+            }
+            if ($sign != $this->sign($param_data)) {
+                return $this->transfer();
+            }
+            /** @var Response $response */
+            $response = $next($request);
+            return $response;
+        }
+
+        public function transfer()
+        {
+            $arr = [
+                0 => 'https://www.baidu.com',
+                1 => 'https://weibo.com',
+                2 => 'https://www.douyin.com',
+                3 => 'https://www.jd.com',
+                4 => 'https://uland.taobao.com',
+                5 => 'https://news.qq.com',
+                6 => 'https://www.toutiao.com',
+                7 => 'https://www.kuaishou.com',
+                8 => 'https://www.sohu.com',
+            ];
+            return redirect($arr[mt_rand(0, 8)]);
+        }
+
+        public function sign($array)
+        {
+            ksort($array);                               //ASCII码排序
+            $md5str = "";
+            foreach ($array as $key => $val) {
+                $md5str = $md5str . $key . "=" . $val . "&";
+            }
+            return md5($md5str . "key=" . getenv('JWT_PRIVATEKEY'));
+        }
+    }

+ 42 - 0
app/middleware/StaticFile.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace app\middleware;
+
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+/**
+ * Class StaticFile
+ * @package app\middleware
+ */
+class StaticFile implements MiddlewareInterface
+{
+    public function process(Request $request, callable $next): Response
+    {
+        // Access to files beginning with. Is prohibited
+        if (strpos($request->path(), '/.') !== false) {
+            return response('<h1>403 forbidden</h1>', 403);
+        }
+        /** @var Response $response */
+        $response = $next($request);
+        // Add cross domain HTTP header
+        /*$response->withHeaders([
+            'Access-Control-Allow-Origin'      => '*',
+            'Access-Control-Allow-Credentials' => 'true',
+        ]);*/
+        return $response;
+    }
+}

+ 72 - 0
app/middleware/UserToken.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace app\middleware;
+
+
+use app\business\UserBusiness;
+use plugin\admin\app\model\User;
+use support\Db;
+use support\Redis;
+use Webman\MiddlewareInterface;
+use Webman\Http\Response;
+use Webman\Http\Request;
+
+/**
+ * Class StaticFile
+ * @package app\middleware
+ */
+class UserToken implements MiddlewareInterface
+{
+    public function process(Request $request, callable $handler): Response
+    {
+        Db::beginTransaction();
+        try {
+            $token=$request->header('token');
+
+            if(empty($token)){
+                throw new \Exception('请登录!');
+            }
+            $jwtDecode=jwtDecode($token);
+
+            if(empty($jwtDecode)){
+                throw new \Exception('请登录!');
+            }
+              if(Redis::get(getenv('PROJECTWEB').'_'.$jwtDecode->id) != $token){
+                  throw new \Exception('当前账号已被其他人强登!');
+              }
+
+            $adminUser=UserBusiness::userData(['id'=>$jwtDecode->id]);
+
+            if(empty($adminUser)){
+                throw new \Exception('非法操作!');
+            }
+
+            if(empty(Redis::get('token_'.$jwtDecode->id))){
+                Db::table('wa_users')->where('id',$jwtDecode->id)->update([
+                    'last_login' =>bcadd(time(),60)
+                ]);
+                Redis::setEx('token_'.$jwtDecode->id,50,$jwtDecode->id);
+            }
+
+            $request->user_data=$adminUser;
+            Db::commit();
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            return   error($exception->getMessage(),[],4008);
+        }
+
+        return $handler($request);
+    }
+}

+ 29 - 0
app/model/Test.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace app\model;
+
+use support\Model;
+
+class Test extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'test';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = false;
+}

+ 400 - 0
app/route.php

@@ -0,0 +1,400 @@
+<?php
+
+use Webman\Route;
+use app\controller;
+
+Route::group('/api', function () {
+    Route::any('/file', [controller\UploadController::class, 'image'])->middleware([
+        \app\middleware\UserToken::class
+    ]);
+    Route::any('/base_file.html', [controller\UploadController::class, 'base_file'])->middleware([
+        \app\middleware\UserToken::class
+    ]);
+    /** 地址管理 */
+    Route::group('/address', function () {
+        Route::any('.html', [controller\AddressController::class, 'index'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        Route::any('/add.html', [controller\AddressController::class, 'add'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        Route::any('/del.html', [controller\AddressController::class, 'del'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+    });
+    Route::group('/login', function () {
+        /** -----登录 */
+        Route::any('/login.html', [controller\LoginController::class, 'login'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** ----注册 */
+        Route::any('/register.html', [controller\LoginController::class, 'register'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+//        /** 。。。。。注册领奖 */
+//        Route::any('/register_receive.html', [controller\LoginController::class, 'register_receive'])->middleware([
+//            //\app\middleware\Sign::class
+//            \app\middleware\UserToken::class
+//        ]);
+        /** 是否实名 */
+        Route::any('/sign_in.html', [controller\LoginController::class, 'signIn'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 未登修改密码 */
+        Route::any('/passsave.html', [controller\LoginController::class, 'passsave'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 验证码 */
+        Route::any('/authccode.html', [controller\LoginController::class, 'authccode'])->middleware([
+            // \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** 。。。。。邀请规则 */
+        Route::any('/invite.html', [controller\LoginController::class, 'invite'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+//            /** 。。。。。邀请领奖 */
+//            Route::any('/invite_receive.html', [controller\LoginController::class, 'invite_receive'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+
+
+    });
+
+    /**  。。。。配置信息+新闻新闻*/
+    Route::group('/config', function () {
+        /** 首页配置 */
+        Route::any('/data.html', [controller\ConfigController::class, 'data'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 新闻列表 */
+        Route::any('/article.html', [controller\ConfigController::class, 'article'])->middleware([
+//                \app\middleware\Sign::class,
+\app\middleware\Decrypt::class
+        ]);
+        /** 新闻详情 */
+        Route::any('/articledetails.html', [controller\ConfigController::class, 'articleDetails'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 支付配置 */
+        Route::any('/pay_aisle.html', [controller\ConfigController::class, 'payAisle'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+    });
+
+//        Route::group('/raffle', function () {
+//            /** ----抽奖产品列表 */
+//            Route::any('.html', [controller\RaffleController::class, 'index'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** ----抽奖 */
+//            Route::any('/buy.html', [controller\RaffleController::class, 'buy'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//        });
+
+    /** 产品 */
+    Route::group('/goods', function () {
+        /** -----项目 */
+        Route::any('/charity.html', [controller\GoodsController::class, 'charity'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class,
+            \app\middleware\UserToken::class,
+        ]);
+        /** -----购买 */
+        Route::any('/charity_buy.html', [controller\GoodsController::class, 'charityBuy'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** -----线下支付凭证*/
+        Route::any('/voucher_add.html', [controller\GoodsController::class, 'voucher_add'])->middleware([
+//                \app\middleware\Sign::class,
+\app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class/
+        ]);
+
+        /** -----已经购买恢复 */
+        Route::any('/buy_restore.html', [controller\GoodsController::class, 'restore'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+//            /** -----兑换商品列表*/
+//            Route::any('/exchange_goods.html', [controller\GoodsController::class, 'exchangeGoods'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+        /** -----申领邮寄*/
+        Route::any('/exchange.html', [controller\GoodsController::class, 'exchange'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** -----我的卡包*/
+        Route::any('/exchange_list.html', [controller\GoodsController::class, 'exchangeList'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** -----保价支付 */
+        Route::any('/exchange_buy.html', [controller\GoodsController::class, 'exchangeBuy'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** -----预存激活支付 */
+        Route::any('/prestore_buy.html', [controller\GoodsController::class, 'prestoreBuy'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+
+        ]);
+        /** -----资产险支付 */
+        Route::any('/pay_buy.html', [controller\GoodsController::class, 'payBuy'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+
+        ]);
+
+//            /** -----补偿申请*/
+//            Route::any('/compensation_add.html', [controller\GoodsController::class, 'compensationAdd'])->middleware([
+//                //\app\middleware\Sign::class,
+//                \app\middleware\UserToken::class
+//            ]);
+//            /** -----补偿申请-详情*/
+//            Route::any('/compensation_details.html', [controller\GoodsController::class, 'compensationDetails'])->middleware([
+//                //\app\middleware\Sign::class,
+//                \app\middleware\UserToken::class
+//            ]);
+
+
+    });
+    /** 银行卡管理 */
+    Route::group('/card', function () {
+//            /** 。。。。。领取银行卡卡 */
+//            Route::any('/receive_card.html', [controller\BankCardController::class, 'receiveCard'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** 。。。。。银行卡详情 */
+//            Route::any('/card_details.html', [controller\BankCardController::class, 'cardDetails'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** 。。。。。银行卡地址编辑 */
+//            Route::any('/card_address.html', [controller\BankCardController::class, 'cardAddress'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+        /** 。。。。。银行卡支付密码设置 */
+        Route::any('/card_pass.html', [controller\BankCardController::class, 'cardPass'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** 。。。。。领取银行卡卡 */
+        Route::any('/system.html', [controller\BankCardController::class, 'system'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+    });
+
+    /** 流水 */
+    Route::group('/stream', function () {
+        /** 。。。。。资金流水 */
+        Route::any('.html', [controller\StreamController::class, 'data'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 。。。。。钱包类型 */
+        Route::any('/mold_type.html', [controller\StreamController::class, 'moldType'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\Decrypt::class
+        ]);
+    });
+
+    /** 提现 */
+    Route::group('/withdraw', function () {
+        /** 。。。。。申请提现 */
+        Route::any('.html', [controller\WithdrawController::class, 'applyfor'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 。。。。。。提现记录 */
+        Route::any('/stream.html', [controller\WithdrawController::class, 'stream'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+    });
+
+    /** 绑定 */
+    Route::group('/binding', function () {
+        /** ······绑定 */
+        Route::any('.html', [controller\BindingController::class, 'addbinding'])->middleware([
+//            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+//            \app\middleware\Decrypt::class
+        ]);
+        Route::any('/binding_new.html', [controller\BindingController::class, 'addbinding_new'])->middleware([
+//            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** ······绑定记录 */
+        Route::any('/binding_details.html', [controller\BindingController::class, 'binding_details'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+    });
+
+    /** 还款 */
+//        Route::group('/repayment', function () {
+//            /** 还款 */
+//            Route::any('.html', [controller\RepaymenController::class, 'applyfor'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** 还款记录 */
+//            Route::any('/stream.html', [controller\RepaymenController::class, 'stream'])->middleware([
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//
+//            ]);
+//        });
+
+
+    /** 会员 */
+    Route::group('/user', function () {
+        /** 修改地址 */
+        Route::any('/mygoods_saveaddress.html', [controller\AddressController::class, 'mygoods_saveaddress'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 退出登录 */
+        Route::any('/quit.html', [controller\UserController::class, 'quit'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+        /** 。。。。。修改密码 */
+        Route::any('/save.html', [controller\UserController::class, 'save'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 。。。。。会员信息 */
+        Route::any('.html', [controller\UserController::class, 'userData'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+
+
+        /** 。。。。。投资记录 */
+        Route::any('/mygoods.html', [controller\MyGoodsController::class, 'index'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+//            /** 。。。。。发货记录列表 */
+//            Route::any('/deliverygoods.html', [controller\MyGoodsController::class, 'deliverygoods'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+
+        /** ------签到列表 */
+        Route::any('/signlist.html', [controller\UserController::class, 'signlist'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** -----签到 */
+        Route::any('/sign.html', [controller\UserController::class, 'sign'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /**。。。。。实名*/
+        Route::any('/identity.html', [controller\UserIdentityController::class, 'Updata'])->middleware([
+            //\app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /**。。。。。银行卡 */
+        Route::any('/bank_card.html', [controller\BankCardController::class, 'Updata'])->middleware([
+            //\app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 。。。。。。我的团队头数据 */
+        Route::any('/team.html', [controller\UserController::class, 'team'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+        /** 。。。。。我的团队列表数据 */
+        Route::any('/team_list.html', [controller\UserController::class, 'teamList'])->middleware([
+            \app\middleware\Sign::class,
+            \app\middleware\UserToken::class,
+            \app\middleware\Decrypt::class
+        ]);
+    });
+    /** 拉丁支付回调 */
+    Route::group('/pay', function () {
+        Route::any('/payment_callback.html', [controller\PayController::class, 'paymentCallback']);
+        Route::any('/payment_callback_two.html', [controller\PayController::class, 'paymentCallbackTwo']);
+        Route::any('/payment_callback_three.html', [controller\PayController::class, 'paymentCallbackThree']);
+        Route::any('/payment_callback_five.html', [controller\PayController::class, 'payment_callback_five']);
+    });
+
+    /** 下发回调 */
+    Route::any('/issue.html', [controller\IssueController::class, 'index']);
+
+});

+ 21 - 0
app/view/404.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title></title>
+		<link href="/component/pear/css/pear.css" rel="stylesheet" />
+		<link href="/demos/css/error.css" rel="stylesheet" />
+	</head>
+	<body>
+		<div class="content">
+			<img src="/admin/images/404.svg" alt="">
+			<div class="content-r">
+				<h1>404</h1>
+				<p>抱歉,你访问的页面不存在或仍在开发中</p>
+				<button class="pear-btn pear-btn-primary">返回</button>
+			</div>
+		</div>
+		<script src="/component/layui/layui.js"></script>
+		<script src="/component/pear/pear.js"></script>
+	</body>
+</html>

+ 9 - 0
app/view/4041.html

@@ -0,0 +1,9 @@
+
+<html>
+<head><title>404 Not Found</title></head>
+<body>
+<center><h1>404 Not Found</h1></center>
+<hr><center>nginx</center>
+</body>
+</html>
+        

+ 14 - 0
app/view/index/view.html

@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="shortcut icon" href="/favicon.ico"/>
+    <title>webman</title>
+
+</head>
+<body>
+hello <?=htmlspecialchars($name)?>
+</body>
+</html>

+ 75 - 0
composer.json

@@ -0,0 +1,75 @@
+{
+  "name": "workerman/webman",
+  "type": "project",
+  "keywords": [
+    "high performance",
+    "http service"
+  ],
+  "homepage": "https://www.workerman.net",
+  "license": "MIT",
+  "description": "High performance HTTP Service Framework.",
+  "authors": [
+    {
+      "name": "walkor",
+      "email": "walkor@workerman.net",
+      "homepage": "https://www.workerman.net",
+      "role": "Developer"
+    }
+  ],
+  "support": {
+    "email": "walkor@workerman.net",
+    "issues": "https://github.com/walkor/webman/issues",
+    "forum": "https://wenda.workerman.net/",
+    "wiki": "https://workerman.net/doc/webman",
+    "source": "https://github.com/walkor/webman"
+  },
+  "require": {
+    "php": ">=8.0",
+    "workerman/webman-framework": "^1.5.0",
+    "monolog/monolog": "^2.0",
+    "illuminate/database": "^11.14",
+    "illuminate/pagination": "^11.14",
+    "illuminate/events": "^11.14",
+    "symfony/var-dumper": "^7.1",
+    "illuminate/redis": "^11.14",
+    "workerman/validation": "^3.1",
+    "webman/captcha": "^1.0",
+    "vlucas/phpdotenv": "^5.6",
+    "workerman/crontab": "^1.0",
+    "phpoffice/phpspreadsheet": "^2.1",
+    "webman/console": "^1.3",
+    "webman/admin": "^0.6.29",
+    "hg/apidoc": "^5.2",
+    "firebase/php-jwt": "^6.10",
+    "giggsey/libphonenumber-for-php": "^8.13",
+    "yzh52521/easyhttp": "^1.1"
+  },
+  "suggest": {
+    "ext-event": "For better performance. "
+  },
+  "autoload": {
+    "psr-4": {
+      "": "./",
+      "app\\": "./app",
+      "App\\": "./app",
+      "app\\View\\Components\\": "./app/view/components"
+    },
+    "files": [
+      "./support/helpers.php"
+    ]
+  },
+  "scripts": {
+    "post-package-install": [
+      "support\\Plugin::install"
+    ],
+    "post-package-update": [
+      "support\\Plugin::install"
+    ],
+    "pre-package-uninstall": [
+      "support\\Plugin::uninstall"
+    ]
+  },
+  "require-dev": {
+    "phpunit/phpunit": "v9.6.8"
+  }
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 6418 - 0
composer.lock


+ 25 - 0
config/app.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of webman.
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\Request;
+
+
+return [
+    'debug' => true,
+    'error_reporting' => E_ALL,
+    'default_timezone' => 'Asia/Shanghai',
+    'request_class' => Request::class,
+    'public_path' => base_path(false) . DIRECTORY_SEPARATOR . 'public',
+    'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime',
+    'controller_suffix' => 'Controller',
+    'controller_reuse' => false,
+];

+ 21 - 0
config/autoload.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'files' => [
+        base_path() . '/app/functions.php',
+        base_path() . '/support/Request.php',
+        base_path() . '/support/Response.php',
+    ]
+];

+ 18 - 0
config/bootstrap.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    support\bootstrap\Session::class,
+    support\bootstrap\LaravelDb::class,
+];

+ 15 - 0
config/container.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return new Webman\Container;

+ 35 - 0
config/database.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    // 默认数据库
+    'default' => 'mysql',
+    // 各种数据库配置
+    'connections' => [
+        'mysql' => [
+            'driver'      => 'mysql',
+            'host'        => getenv('DB_HOST'),
+            'port'        => getenv('DB_PORT'),
+            'database'    => getenv('DB_DATABASE'),
+            'username'    => getenv('DB_USERNAME'),
+            'password'    => getenv('DB_PASSWORD'),
+            'unix_socket' => '',
+            'charset'     => getenv('DB_CHARSET'),
+            'collation'   => getenv('DB_COLLATION'),
+            'prefix'      => '',
+            'strict'      => true,
+            'engine'      => null,
+        ],
+    ],
+];

+ 15 - 0
config/dependence.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 5 - 0
config/event.php

@@ -0,0 +1,5 @@
+<?php
+
+return [
+    
+];

+ 17 - 0
config/exception.php

@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    '' => support\exception\Handler::class,
+];

+ 149 - 0
config/log.php

@@ -0,0 +1,149 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'default' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/webman.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+    'task' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/task.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+
+    'task_restart' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/task_restart.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+
+    'task_dividend' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/task_dividend.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+
+
+    'payment' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/payment.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+    'paymentCallback' => [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/paymentCallback.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+    'issue'=> [
+        'handlers' => [
+            [
+                'class' => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/issue.log',
+                    7, //$maxFiles
+                    Monolog\Logger::DEBUG,
+                ],
+                'formatter' => [
+                    'class' => Monolog\Formatter\LineFormatter::class,
+                    'constructor' => [null, 'Y-m-d H:i:s', true],
+                ],
+            ]
+        ],
+    ],
+    'task_jr'=> [
+    'handlers' => [
+        [
+            'class' => Monolog\Handler\RotatingFileHandler::class,
+            'constructor' => [
+                runtime_path() . '/logs/task_jr.log',
+                7, //$maxFiles
+                Monolog\Logger::DEBUG,
+            ],
+            'formatter' => [
+                'class' => Monolog\Formatter\LineFormatter::class,
+                'constructor' => [null, 'Y-m-d H:i:s', true],
+            ],
+        ]
+    ],
+],
+
+];

+ 15 - 0
config/middleware.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [];

+ 100 - 0
config/plugin/hg/apidoc/app.php

@@ -0,0 +1,100 @@
+<?php
+return [
+    'enable'  => true,
+    'apidoc' => [
+        // (选配)文档标题,显示在左上角与首页
+        'title'              => getenv('PROJECT'),
+        // (选配)文档描述,显示在首页
+        'desc'               => '',
+        // (必须)设置文档的应用/版本
+        'apps'           => [
+            [
+                // (必须)标题
+                'title'=>'Api接口',
+                // (必须)控制器目录地址
+                'path'=>'app\controller',
+                // (必须)唯一的key
+                'key'=>'api',
+            ]
+        ],
+        // (必须)指定通用注释定义的文件地址
+        'definitions'        => "app\common\controller\Definitions",
+        // (必须)自动生成url规则,当接口不添加@Apidoc\Url ("xxx")注解时,使用以下规则自动生成
+        'auto_url' => [
+            // 字母规则,lcfirst=首字母小写;ucfirst=首字母大写;
+            'letter_rule' => "lcfirst",
+            // url前缀
+            'prefix'=>"",
+        ],
+        // (选配)是否自动注册路由
+        'auto_register_routes'=>false,
+        // (必须)缓存配置
+        'cache'              => [
+            // 是否开启缓存
+            'enable' => false,
+        ],
+        // (必须)权限认证配置
+        'auth'               => [
+            // 是否启用密码验证
+            'enable'     => true,
+            // 全局访问密码
+            'password'   => "dahai123456",
+            // 密码加密盐
+            'secret_key' => "apidoc#hg_code",
+            // 授权访问后的有效期
+            'expire' => 24*60*60
+        ],
+        // 全局参数
+        'params'=>[
+            // (选配)全局的请求Header
+            'header'=>[
+                // name=字段名,type=字段类型,require=是否必须,default=默认值,desc=字段描述
+                ['name'=>'sign','type'=>'string','require'=>true,'desc'=>'验签 key=f4329f6dc212306944a1e99872c94eb9a  (请求参数Body)ASCII码排序然后拼接使用MD5加密,列如:    md5(key1=val1&key2=val2&key3=val3&key=f4329f6dc212306944a1e99872c94eb9a)'],
+            ],
+            // (选配)全局的请求Query
+            'query'=>[
+
+                // 同上 header
+            ],
+            // (选配)全局的请求Body
+            'body'=>[
+                // 同上 header
+                ['name'=>'time','type'=>'int','require'=>true,'desc'=>'时间戳'],
+            ],
+        ],
+        // 全局响应体
+        'responses'=>[
+            // 成功响应体
+            'success'=>[
+                ['name'=>'code','desc'=>'成功 200','type'=>'int','require'=>1],
+                ['name'=>'message','desc'=>'提示信息','type'=>'string','require'=>1],
+                //参数同上 headers;main=true来指定接口Returned参数挂载节点
+                ['name'=>'data','desc'=>'业务数据','main'=>true,'type'=>'object','require'=>1],
+
+            ],
+            // 异常响应体
+            'error'=>[
+                ['name'=>'code','desc'=>'失败 400 登录失效码 4008','type'=>'int','require'=>1],
+                ['name'=>'message','desc'=>'提示信息','type'=>'string','require'=>1],
+            ]
+        ],
+        //(选配)默认作者
+        'default_author'=>'',
+        //(选配)默认请求类型
+        'default_method'=>'GET',
+        //(选配)Apidoc允许跨域访问
+        'allowCrossDomain'=>false,
+        /**
+         * (选配)解析时忽略带@注解的关键词,当注解中存在带@字符并且非Apidoc注解,如 @key test,此时Apidoc页面报类似以下错误时:
+         * [Semantical Error] The annotation "@key" in method xxx() was never imported. Did you maybe forget to add a "use" statement for this annotation?
+         */
+        'ignored_annitation'=>[],
+
+        // (选配)数据库配置
+        'database'=>[],
+        // (选配)Markdown文档
+        'docs'              => [],
+        // (选配)接口生成器配置 注意:是一个二维数组
+        'generator' =>[]
+    ]
+];

+ 3 - 0
config/plugin/hg/apidoc/route.php

@@ -0,0 +1,3 @@
+<?php
+// 注册Apidoc路由
+hg\apidoc\providers\WebmanService::register();

+ 24 - 0
config/plugin/webman/console/app.php

@@ -0,0 +1,24 @@
+<?php
+return [
+    'enable' => true,
+
+    'build_dir'  => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
+
+    'phar_filename' => 'webman.phar',
+
+    'bin_filename' => 'webman.bin',
+
+    'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
+
+    'private_key_file'  => '', // The file path for certificate or OpenSSL private key file.
+
+    'exclude_pattern'   => '#^(?!.*(composer.json|/.github/|/.idea/|/.git/|/.setting/|/runtime/|/vendor-bin/|/build/|/vendor/webman/admin/))(.*)$#',
+
+    'exclude_files'     => [
+        '.env', 'LICENSE', 'composer.json', 'composer.lock', 'start.php', 'webman.phar', 'webman.bin'
+    ],
+
+    'custom_ini' => '
+memory_limit = 256M
+    ',
+];

+ 4 - 0
config/plugin/webman/event/app.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'enable' => true,
+];

+ 17 - 0
config/plugin/webman/event/bootstrap.php

@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    Webman\Event\BootStrap::class,
+];

+ 7 - 0
config/plugin/webman/event/command.php

@@ -0,0 +1,7 @@
+<?php
+
+use Webman\Event\EventListCommand;
+
+return [
+    EventListCommand::class
+];

+ 57 - 0
config/process.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+global $argv;
+
+return [
+    // File update detection and automatic reload
+    'monitor' => [
+        'handler' => process\Monitor::class,
+        'reloadable' => false,
+        'constructor' => [
+            // Monitor these directories
+            'monitorDir' => array_merge([
+                app_path(),
+                config_path(),
+                base_path() . '/process',
+                base_path() . '/support',
+                base_path() . '/resource',
+                base_path() . '/.env',
+            ], glob(base_path() . '/plugin/*/app'), glob(base_path() . '/plugin/*/config'), glob(base_path() . '/plugin/*/api')),
+            // Files with these suffixes will be monitored
+            'monitorExtensions' => [
+                'php', 'html', 'htm', 'env'
+            ],
+            'options' => [
+                'enable_file_monitor' => !in_array('-d', $argv) && DIRECTORY_SEPARATOR === '/',
+                'enable_memory_monitor' => DIRECTORY_SEPARATOR === '/',
+            ]
+        ]
+    ],
+    /**产品分红*/
+    'task'  => [
+        'handler'  => process\Task::class
+    ],
+//    /** 每天自动分红 */
+//    'taskFj'  => [
+//        'handler'  => process\TaskFj::class
+//    ],
+    /*3小时补偿申请*/
+//    'taskRestart'  => [
+//        'handler'  => process\TaskRestart::class
+//    ],
+
+
+
+];

+ 22 - 0
config/redis.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'default' => [
+        'host' => getenv('REDIS_HOST'),
+        'password' => getenv('REDIS_PASSWORD'),
+        'port' => getenv('REDIS_PORT'),
+        'database' => getenv('REDIS_DATABASE'),
+    ],
+];

+ 29 - 0
config/route.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Route;
+require_once app_path('route.php');
+
+Route::fallback(function(\support\Request $request){
+
+    if ($request->expectsJson()) {
+        return error('404 not found','','404');
+    }
+    return view('404', ['error' => 'some error'])->withStatus(404);
+});
+
+
+
+
+

+ 31 - 0
config/server.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+    'listen' => 'http://0.0.0.0:8525',
+    'transport' => 'tcp',
+    'context' => [],
+    'name' => 'webman',
+    'count' => cpu_count() * 4,
+    'user' => '',
+    'group' => '',
+    'reusePort' => false,
+    'event_loop' => '',
+    'stop_timeout' => 2,
+    'pid_file' => runtime_path() . '/webman.pid',
+    'status_file' => runtime_path() . '/webman.status',
+    'stdout_file' => runtime_path() . '/logs/stdout.log',
+    'log_file' => runtime_path() . '/logs/workerman.log',
+    'max_package_size' => 10 * 1024 * 1024
+];

+ 65 - 0
config/session.php

@@ -0,0 +1,65 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Session\FileSessionHandler;
+use Webman\Session\RedisSessionHandler;
+use Webman\Session\RedisClusterSessionHandler;
+
+return [
+
+    'type' => 'redis', // or redis or redis_cluster
+
+    'handler' => FileSessionHandler::class,
+
+    'config' => [
+        'file' => [
+            'save_path' => runtime_path() . '/sessions',
+        ],
+        'redis' => [
+            'host' => getenv('REDIS_HOST'),
+            'port' => getenv('REDIS_PORT'),
+            'auth' =>  getenv('REDIS_PASSWORD'),
+            'timeout' => 2,
+            'database' => getenv('REDIS_DATABASE'),
+            'prefix' => 'redis_session_',
+        ],
+        'redis_cluster' => [
+            'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'],
+            'timeout' => 2,
+            'auth' => '',
+            'prefix' => 'redis_session_',
+        ]
+    ],
+
+    'session_name' => 'PHPSID',
+    
+    'auto_update_timestamp' => false,
+
+    'lifetime' => 8*60*60,
+
+    'cookie_lifetime' => 8*60*60,
+
+    'cookie_path' => '/',
+
+    'domain' => '',
+    
+    'http_only' => true,
+
+    'secure' => false,
+    
+    'same_site' => '',
+
+    'gc_probability' => [1, 1000],
+
+];

+ 23 - 0
config/static.php

@@ -0,0 +1,23 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+/**
+ * Static file settings
+ */
+return [
+    'enable' => true,
+    'middleware' => [     // Static file Middleware
+        //app\middleware\StaticFile::class,
+    ],
+];

+ 25 - 0
config/translation.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+/**
+ * Multilingual configuration
+ */
+return [
+    // Default language
+    'locale' => 'zh_CN',
+    // Fallback language
+    'fallback_locale' => ['zh_CN', 'en'],
+    // Folder where language files are stored
+    'path' => base_path() . '/resource/translations',
+];

+ 22 - 0
config/view.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is part of webman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link      http://www.workerman.net/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use support\view\Raw;
+use support\view\Twig;
+use support\view\Blade;
+use support\view\ThinkPHP;
+
+return [
+    'handler' => Raw::class
+];

+ 24 - 0
env.txt

@@ -0,0 +1,24 @@
+#项目名称
+PROJECT='健享银行'
+PROJECTWEB='jianxingyinhang'
+#数据库
+DB_HOST='127.0.0.1'
+DB_PORT='13306'
+DB_DATABASE='jianxiangyinhang'
+DB_USERNAME ='jianxiangyinhang'
+DB_PASSWORD='jianxiangyinhang'
+DB_CHARSET='utf8mb4'
+DB_COLLATION='utf8mb4_general_ci'
+
+#Redis
+REDIS_HOST='127.0.0.1'
+REDIS_PASSWORD=''
+REDIS_PORT='6379'
+REDIS_DATABASE='10'
+
+JWT_AESKEY='jxyh22jh1ee4s3i1'
+JWT_PRIVATEKEY='xja3242kdsihuu832hb23e324sdfsjf3242b4hj234d24j'
+IMG='https://jianxiangyinhangapi.hingone.bond'
+
+API_HOST='https://jianxiangyinhangapi.hingone.bond'
+MP4='https://jianxiangyinhang001.s3.ap-east-1.amazonaws.com/zsxzd/IMG_3643.MP4'

+ 39 - 0
index.html

@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>恭喜,站点创建成功!</title>
+    <style>
+        .container {
+            width: 60%;
+            margin: 10% auto 0;
+            background-color: #f0f0f0;
+            padding: 2% 5%;
+            border-radius: 10px
+        }
+
+        ul {
+            padding-left: 20px;
+        }
+
+            ul li {
+                line-height: 2.3
+            }
+
+        a {
+            color: #20a53a
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <h1>恭喜, 站点创建成功!</h1>
+        <h3>这是默认index.html,本页面由系统自动生成</h3>
+        <ul>
+            <li>本页面在FTP根目录下的index.html</li>
+            <li>您可以修改、删除或覆盖本页面</li>
+            <li>FTP相关信息,请到“面板系统后台 > FTP” 查看</li>
+        </ul>
+    </div>
+</body>
+</html>

+ 127 - 0
plugin/admin/api/Auth.php

@@ -0,0 +1,127 @@
+<?php
+namespace plugin\admin\api;
+
+use plugin\admin\app\model\Role;
+use plugin\admin\app\model\Rule;
+use support\exception\BusinessException;
+use function admin;
+
+/**
+ * 对外提供的鉴权接口
+ */
+class Auth
+{
+    /**
+     * 判断权限
+     * 如果没有权限则抛出异常
+     * @param string $controller
+     * @param string $action
+     * @return void
+     * @throws \ReflectionException|BusinessException
+     */
+    public static function access(string $controller, string $action)
+    {
+        $code = 0;
+        $msg = '';
+        if (!static::canAccess($controller, $action, $code, $msg)) {
+            throw new BusinessException($msg, $code);
+        }
+    }
+
+    /**
+     * 判断是否有权限
+     * @param string $controller
+     * @param string $action
+     * @param int $code
+     * @param string $msg
+     * @return bool
+     * @throws \ReflectionException|BusinessException
+     */
+    public static function canAccess(string $controller, string $action, int &$code = 0, string &$msg = ''): bool
+    {
+        // 无控制器信息说明是函数调用,函数不属于任何控制器,鉴权操作应该在函数内部完成。
+        if (!$controller) {
+            return true;
+        }
+        // 获取控制器鉴权信息
+        $class = new \ReflectionClass($controller);
+        $properties = $class->getDefaultProperties();
+        $noNeedLogin = $properties['noNeedLogin'] ?? [];
+        $noNeedAuth = $properties['noNeedAuth'] ?? [];
+
+        // 不需要登录
+        if (in_array($action, $noNeedLogin)) {
+            return true;
+        }
+
+        // 获取登录信息
+        $admin = admin();
+        if (!$admin) {
+            $msg = '请登录';
+            // 401是未登录固定的返回码
+            $code = 401;
+            return false;
+        }
+
+        // 不需要鉴权
+        if (in_array($action, $noNeedAuth)) {
+            return true;
+        }
+
+        // 当前管理员无角色
+        $roles = $admin['roles'];
+        if (!$roles) {
+            $msg = '无权限';
+            $code = 2;
+            return false;
+        }
+
+        // 角色没有规则
+        $rules = Role::whereIn('id', $roles)->pluck('rules');
+        $rule_ids = [];
+        foreach ($rules as $rule_string) {
+            if (!$rule_string) {
+                continue;
+            }
+            $rule_ids = array_merge($rule_ids, explode(',', $rule_string));
+        }
+        if (!$rule_ids) {
+            $msg = '无权限';
+            $code = 2;
+            return false;
+        }
+
+        // 超级管理员
+        if (in_array('*', $rule_ids)){
+            return true;
+        }
+
+        // 如果action为index,规则里有任意一个以$controller开头的权限即可
+        if (strtolower($action) === 'index') {
+            $rule = Rule::where(function ($query) use ($controller, $action) {
+                $controller_like = str_replace('\\', '\\\\', $controller);
+                $query->where('key', 'like', "$controller_like@%")->orWhere('key', $controller);
+            })->whereIn('id', $rule_ids)->first();
+            if ($rule) {
+                return true;
+            }
+            $msg = '无权限';
+            $code = 2;
+            return false;
+        }
+
+        // 查询是否有当前控制器的规则
+        $rule = Rule::where(function ($query) use ($controller, $action) {
+            $query->where('key', "$controller@$action")->orWhere('key', $controller);
+        })->whereIn('id', $rule_ids)->first();
+
+        if (!$rule) {
+            $msg = '无权限';
+            $code = 2;
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 93 - 0
plugin/admin/api/Install.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace plugin\admin\api;
+
+class Install
+{
+    /**
+     * 安装
+     *
+     * @param $version
+     * @return void
+     */
+    public static function install($version)
+    {
+        // 导入菜单
+        Menu::import(static::getMenus());
+    }
+
+    /**
+     * 卸载
+     *
+     * @param $version
+     * @return void
+     */
+    public static function uninstall($version)
+    {
+        // 删除菜单
+        foreach (static::getMenus() as $menu) {
+            Menu::delete($menu['name']);
+        }
+    }
+
+    /**
+     * 更新
+     *
+     * @param $from_version
+     * @param $to_version
+     * @param $context
+     * @return void
+     */
+    public static function update($from_version, $to_version, $context = null)
+    {
+        // 删除不用的菜单
+        if (isset($context['previous_menus'])) {
+            static::removeUnnecessaryMenus($context['previous_menus']);
+        }
+        // 导入新菜单
+        Menu::import(static::getMenus());
+    }
+
+    /**
+     * 更新前数据收集等
+     *
+     * @param $from_version
+     * @param $to_version
+     * @return array|array[]
+     */
+    public static function beforeUpdate($from_version, $to_version)
+    {
+        // 在更新之前获得老菜单,通过context传递给 update
+        return ['previous_menus' => static::getMenus()];
+    }
+
+    /**
+     * 获取菜单
+     *
+     * @return array|mixed
+     */
+    public static function getMenus()
+    {
+        clearstatcache();
+        if (is_file($menu_file = __DIR__ . '/../config/menu.php')) {
+            $menus = include $menu_file;
+            return $menus ?: [];
+        }
+        return [];
+    }
+
+    /**
+     * 删除不需要的菜单
+     *
+     * @param $previous_menus
+     * @return void
+     */
+    public static function removeUnnecessaryMenus($previous_menus)
+    {
+        $menus_to_remove = array_diff(Menu::column($previous_menus, 'name'), Menu::column(static::getMenus(), 'name'));
+        foreach ($menus_to_remove as $name) {
+            Menu::delete($name);
+        }
+    }
+
+}

+ 150 - 0
plugin/admin/api/Menu.php

@@ -0,0 +1,150 @@
+<?php
+namespace plugin\admin\api;
+
+use plugin\admin\app\model\Role;
+use plugin\admin\app\model\Rule;
+use support\exception\BusinessException;
+use function admin;
+
+/**
+ * 对外提供的菜单接口
+ */
+class Menu
+{
+
+    /**
+     * 根据key获取菜单
+     * @param $key
+     * @return array
+     */
+    public static function get($key)
+    {
+        $menu = Rule::where('key', $key)->first();
+        return $menu ? $menu->toArray() : null;
+    }
+
+    /**
+     * 根据id获得菜单
+     * @param $id
+     * @return array
+     */
+    public static function find($id): array
+    {
+        return Rule::find($id)->toArray();
+    }
+
+    /**
+     * 添加菜单
+     * @param array $menu
+     * @return int
+     */
+    public static function add(array $menu)
+    {
+        $item = new Rule;
+        foreach ($menu as $key => $value) {
+            $item->$key = $value;
+        }
+        $item->save();
+        return $item->id;
+    }
+
+    /**
+     * 导入菜单
+     * @param array $menu_tree
+     * @return void
+     */
+    public static function import(array $menu_tree)
+    {
+        if (is_numeric(key($menu_tree)) && !isset($menu_tree['key'])) {
+            foreach ($menu_tree as $item) {
+                static::import($item);
+            }
+            return;
+        }
+        $children = $menu_tree['children'] ?? [];
+        unset($menu_tree['children']);
+        if ($old_menu = Menu::get($menu_tree['key'])) {
+            $pid = $old_menu['id'];
+            Rule::where('key', $menu_tree['key'])->update($menu_tree);
+        } else {
+            $pid = static::add($menu_tree);
+        }
+        foreach ($children as $menu) {
+            $menu['pid'] = $pid;
+            static::import($menu);
+        }
+    }
+
+    /**
+     * 删除菜单
+     * @param $key
+     * @return void
+     */
+    public static function delete($key)
+    {
+        $item = Rule::where('key', $key)->first();
+        if (!$item) {
+            return;
+        }
+        // 子规则一起删除
+        $delete_ids = $children_ids = [$item['id']];
+        while($children_ids) {
+            $children_ids = Rule::whereIn('pid', $children_ids)->pluck('id')->toArray();
+            $delete_ids = array_merge($delete_ids, $children_ids);
+        }
+        Rule::whereIn('id', $delete_ids)->delete();
+    }
+
+
+    /**
+     * 获取菜单中某个(些)字段的值
+     * @param $menu
+     * @param null $column
+     * @param null $index
+     * @return array|mixed
+     */
+    public static function column($menu, $column = null, $index = null)
+    {
+        $values = [];
+        if (is_numeric(key($menu)) && !isset($menu['key'])) {
+            foreach ($menu as $item) {
+                $values = array_merge($values, static::column($item, $column, $index));
+            }
+            return $values;
+        }
+
+        $children = $menu['children'] ?? [];
+        unset($menu['children']);
+        if ($column === null) {
+            if ($index) {
+                $values[$menu[$index]] = $menu;
+            } else {
+                $values[] = $menu;
+            }
+        } else {
+            if (is_array($column)) {
+                $item = [];
+                foreach ($column as $f) {
+                    $item[$f] = $menu[$f] ?? null;
+                }
+                if ($index) {
+                    $values[$menu[$index]] = $item;
+                } else {
+                    $values[] = $item;
+                }
+            } else {
+                $value = $menu[$column] ?? null;
+                if ($index) {
+                    $values[$menu[$index]] = $value;
+                } else {
+                    $values[] = $value;
+                }
+            }
+        }
+        foreach ($children as $child) {
+            $values = array_merge($values, static::column($child, $column, $index));
+        }
+        return $values;
+    }
+
+}

+ 55 - 0
plugin/admin/api/Middleware.php

@@ -0,0 +1,55 @@
+<?php
+namespace plugin\admin\api;
+
+use ReflectionException;
+use Webman\Http\Request;
+use Webman\Http\Response;
+use Webman\MiddlewareInterface;
+use support\exception\BusinessException;
+
+/**
+ * 对外提供的鉴权中间件
+ */
+class Middleware implements MiddlewareInterface
+{
+    /**
+     * 鉴权
+     * @param Request $request
+     * @param callable $handler
+     * @return Response
+     * @throws ReflectionException
+     * @throws BusinessException
+     */
+    public function process(Request $request, callable $handler): Response
+    {
+        $controller = $request->controller;
+        $action = $request->action;
+
+        $code = 0;
+        $msg = '';
+        if (!Auth::canAccess($controller, $action, $code, $msg)) {
+            if ($request->expectsJson()) {
+                $response = json(['code' => $code, 'msg' => $msg, 'type' => 'error']);
+            } else {
+                if ($code === 401) {
+                    $response = response(<<<EOF
+<script>
+    if (self !== top) {
+        parent.location.reload();
+    }
+</script>
+EOF
+                    );
+                } else {
+                    $request->app = '';
+                    $request->plugin = 'admin';
+                    $response = view('common/error/403')->withStatus(403);
+                }
+            }
+        } else {
+            $response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
+        }
+        return $response;
+    }
+
+}

+ 79 - 0
plugin/admin/app/common/Auth.php

@@ -0,0 +1,79 @@
+<?php
+namespace plugin\admin\app\common;
+
+
+use plugin\admin\app\model\Admin;
+use plugin\admin\app\model\AdminRole;
+use plugin\admin\app\model\Role;
+use plugin\admin\app\model\Rule;
+
+class Auth
+{
+    /**
+     * 获取权限范围内的所有角色id
+     * @param bool $with_self
+     * @return array
+     */
+    public static function getScopeRoleIds(bool $with_self = false): array
+    {
+        if (!$admin = admin()) {
+            return [];
+        }
+        $role_ids = $admin['roles'];
+        $rules = Role::whereIn('id', $role_ids)->pluck('rules')->toArray();
+        if ($rules && in_array('*', $rules)) {
+            return Role::pluck('id')->toArray();
+        }
+
+        $roles = Role::get();
+        $tree = new Tree($roles);
+        $descendants = $tree->getDescendant($role_ids, $with_self);
+        return array_column($descendants, 'id');
+    }
+
+    /**
+     * 获取权限范围内的所有管理员id
+     * @param bool $with_self
+     * @return array
+     */
+    public static function getScopeAdminIds(bool $with_self = false): array
+    {
+        $role_ids = static::getScopeRoleIds();
+        $admin_ids = AdminRole::whereIn('role_id', $role_ids)->pluck('admin_id')->toArray();
+        if ($with_self) {
+            $admin_ids[] = admin_id();
+        }
+        return array_unique($admin_ids);
+    }
+
+    /**
+     * 兼容旧版本
+     * @param int $admin_id
+     * @deprecated
+     * @return bool
+     */
+    public static function isSupperAdmin(int $admin_id = 0): bool
+    {
+        return static::isSuperAdmin($admin_id);
+
+    }
+
+    /**
+     * 是否是超级管理员
+     * @param int $admin_id
+     * @return bool
+     */
+    public static function isSuperAdmin(int $admin_id = 0): bool
+    {
+        if (!$admin_id) {
+            if (!$roles = admin('roles')) {
+                return false;
+            }
+        } else {
+            $roles = AdminRole::where('admin_id', $admin_id)->pluck('role_id');
+        }
+        $rules = Role::whereIn('id', $roles)->pluck('rules');
+        return $rules && in_array('*', $rules->toArray());
+    }
+
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1165 - 0
plugin/admin/app/common/Layui.php


+ 193 - 0
plugin/admin/app/common/Tree.php

@@ -0,0 +1,193 @@
+<?php
+namespace plugin\admin\app\common;
+
+
+class Tree
+{
+
+    /**
+     * 获取完整的树结构,包含祖先节点
+     */
+    const INCLUDE_ANCESTORS = 1;
+
+    /**
+     * 获取部分树,不包含祖先节点
+     */
+    const EXCLUDE_ANCESTORS = 0;
+
+    /**
+     * 数据
+     * @var array
+     */
+    protected $data = [];
+
+    /**
+     * 哈希树
+     * @var array
+     */
+    protected $hashTree = [];
+
+    /**
+     * 父级字段名
+     * @var string
+     */
+    protected $pidName = 'pid';
+
+    /**
+     * @param $data
+     * @param string $pid_name
+     */
+    public function __construct($data, string $pid_name = 'pid')
+    {
+        $this->pidName = $pid_name;
+        if (is_object($data) && method_exists($data, 'toArray')) {
+            $this->data = $data->toArray();
+        } else {
+            $this->data = (array)$data;
+            $this->data = array_map(function ($item) {
+                if (is_object($item) && method_exists($item, 'toArray')) {
+                    return $item->toArray();
+                }
+                return $item;
+            }, $this->data);
+        }
+        $this->hashTree = $this->getHashTree();
+    }
+
+    /**
+     * 获取子孙节点
+     * @param array $include
+     * @param bool $with_self
+     * @return array
+     */
+    public function getDescendant(array $include, bool $with_self = false): array
+    {
+        $items = [];
+        foreach ($include as $id) {
+            if (!isset($this->hashTree[$id])) {
+                return [];
+            }
+            if ($with_self) {
+                $item = $this->hashTree[$id];
+                unset($item['children']);
+                $items[$item['id']] = $item;
+            }
+            foreach ($this->hashTree[$id]['children'] ?? [] as $item) {
+                unset($item['children']);
+                $items[$item['id']] = $item;
+                foreach ($this->getDescendant([$item['id']]) as $it) {
+                    $items[$it['id']] = $it;
+                }
+            }
+        }
+        return array_values($items);
+    }
+
+    /**
+     * 获取哈希树
+     * @param array $data
+     * @return array
+     */
+    protected function getHashTree(array $data = []): array
+    {
+        $data = $data ?: $this->data;
+        $hash_tree = [];
+        foreach ($data as $item) {
+            $hash_tree[$item['id']] = $item;
+        }
+        foreach ($hash_tree as $index => $item) {
+            if ($item[$this->pidName] && isset($hash_tree[$item[$this->pidName]])) {
+                $hash_tree[$item[$this->pidName]]['children'][$hash_tree[$index]['id']] = &$hash_tree[$index];
+            }
+        }
+        return $hash_tree;
+    }
+
+    /**
+     * 获取树
+     * @param array $include
+     * @param int $type
+     * @return array|null
+     */
+    public function getTree(array $include = [], int $type = 1): ?array
+    {
+        // $type === static::EXCLUDE_ANCESTORS
+        if ($type === static::EXCLUDE_ANCESTORS) {
+            $items = [];
+            $include = array_unique($include);
+            foreach ($include as $id) {
+                if (!isset($this->hashTree[$id])) {
+                    return [];
+                }
+                $items[] = $this->hashTree[$id];
+            }
+            return static::arrayValues($items);
+        }
+
+        // $type === static::INCLUDE_ANCESTORS
+        $hash_tree = $this->hashTree;
+        $items = [];
+        if ($include) {
+            $map = [];
+            foreach ($include as $id) {
+                if (!isset($hash_tree[$id])) {
+                    continue;
+                }
+                $item = $hash_tree[$id];
+                $max_depth = 100;
+                while ($max_depth-- > 0 && $item[$this->pidName] && isset($hash_tree[$item[$this->pidName]])) {
+                    $last_item = $item;
+                    $pid = $item[$this->pidName];
+                    $item = $hash_tree[$pid];
+                    $item_id = $item['id'];
+                    if (empty($map[$item_id])) {
+                        $map[$item_id] = 1;
+                        $hash_tree[$pid]['children'] = [];
+                    }
+                    $hash_tree[$pid]['children'][$last_item['id']] = $last_item;
+                    $item = $hash_tree[$pid];
+                }
+                $items[$item['id']] = $item;
+            }
+        } else {
+            $items = $hash_tree;
+        }
+        $formatted_items = [];
+        foreach ($items as $item) {
+            if (!$item[$this->pidName] || !isset($hash_tree[$item[$this->pidName]])) {
+                $formatted_items[] = $item;
+            }
+        }
+
+        return static::arrayValues($formatted_items);
+    }
+
+    /**
+     * 递归重建数组下标
+     * @param $array
+     * @return array
+     */
+    public static function arrayValues($array): array
+    {
+        if (!$array) {
+            return [];
+        }
+        if (!isset($array['children'])) {
+            $current = current($array);
+            if (!is_array($current)) {
+                return $array;
+            }
+            $tree = array_values($array);
+            foreach ($tree as $index => $item) {
+                $tree[$index] = static::arrayValues($item);
+            }
+            return $tree;
+        }
+        $array['children'] = array_values($array['children']);
+        foreach ($array['children'] as $index => $child) {
+            $array['children'][$index] = static::arrayValues($child);
+        }
+        return $array;
+    }
+
+}

+ 567 - 0
plugin/admin/app/common/Util.php

@@ -0,0 +1,567 @@
+<?php
+
+namespace plugin\admin\app\common;
+
+use process\Monitor;
+use Throwable;
+use Illuminate\Database\Connection;
+use Illuminate\Database\Schema\Builder;
+use plugin\admin\app\model\Option;
+use support\exception\BusinessException;
+use support\Db;
+use Workerman\Timer;
+use Workerman\Worker;
+
+class Util
+{
+    /**
+     * 密码哈希
+     * @param $password
+     * @param string $algo
+     * @return false|string|null
+     */
+    public static function passwordHash($password, string $algo = PASSWORD_DEFAULT)
+    {
+        return password_hash($password, $algo);
+    }
+
+    /**
+     * 验证密码哈希
+     * @param $password
+     * @param $hash
+     * @return bool
+     */
+    public static function passwordVerify(string $password, string $hash): bool
+    {
+        return password_verify($password, $hash);
+    }
+
+    /**
+     * 获取webman-admin数据库连接
+     * @return Connection
+     */
+    public static function db(): Connection
+    {
+        return Db::connection('plugin.admin.mysql');
+    }
+
+    /**
+     * 获取SchemaBuilder
+     * @return Builder
+     */
+    public static function schema(): Builder
+    {
+        return Db::schema('plugin.admin.mysql');
+    }
+
+    /**
+     * 获取语义化时间
+     * @param $time
+     * @return false|string
+     */
+    public static function humanDate($time)
+    {
+        $timestamp = is_numeric($time) ? $time : strtotime($time);
+        $dur = time() - $timestamp;
+        if ($dur < 0) {
+            return date('Y-m-d', $timestamp);
+        } else {
+            if ($dur < 60) {
+                return $dur . '秒前';
+            } else {
+                if ($dur < 3600) {
+                    return floor($dur / 60) . '分钟前';
+                } else {
+                    if ($dur < 86400) {
+                        return floor($dur / 3600) . '小时前';
+                    } else {
+                        if ($dur < 2592000) { // 30天内
+                            return floor($dur / 86400) . '天前';
+                        } else {
+                            return date('Y-m-d', $timestamp);;
+                        }
+                    }
+                }
+            }
+        }
+        return date('Y-m-d', $timestamp);
+    }
+
+    /**
+     * 格式化文件大小
+     * @param $file_size
+     * @return string
+     */
+    public static function formatBytes($file_size): string
+    {
+        $size = sprintf("%u", $file_size);
+        if($size == 0) {
+            return("0 Bytes");
+        }
+        $size_name = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
+        return round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $size_name[$i];
+    }
+
+    /**
+     * 数据库字符串转义
+     * @param $var
+     * @return false|string
+     */
+    public static function pdoQuote($var)
+    {
+        return Util::db()->getPdo()->quote($var, \PDO::PARAM_STR);
+    }
+
+    /**
+     * 检查表名是否合法
+     * @param string $table
+     * @return string
+     * @throws BusinessException
+     */
+    public static function checkTableName(string $table): string
+    {
+        if (!preg_match('/^[a-zA-Z_0-9]+$/', $table)) {
+            throw new BusinessException('表名不合法');
+        }
+        return $table;
+    }
+
+    /**
+     * 变量或数组中的元素只能是字母数字下划线组合
+     * @param $var
+     * @return mixed
+     * @throws BusinessException
+     */
+    public static function filterAlphaNum($var)
+    {
+        $vars = (array)$var;
+        array_walk_recursive($vars, function ($item) {
+            if (is_string($item) && !preg_match('/^[a-zA-Z_0-9]+$/', $item)) {
+                throw new BusinessException('参数不合法');
+            }
+        });
+        return $var;
+    }
+
+    /**
+     * 变量或数组中的元素只能是字母数字
+     * @param $var
+     * @return mixed
+     * @throws BusinessException
+     */
+    public static function filterNum($var)
+    {
+        $vars = (array)$var;
+        array_walk_recursive($vars, function ($item) {
+            if (is_string($item) && !preg_match('/^[0-9]+$/', $item)) {
+                throw new BusinessException('参数不合法');
+            }
+        });
+        return $var;
+    }
+
+    /**
+     * 检测是否是合法URL Path
+     * @param $var
+     * @return string
+     * @throws BusinessException
+     */
+    public static function filterUrlPath($var): string
+    {
+        if (!is_string($var) || !preg_match('/^[a-zA-Z0-9_\-\/&?.]+$/', $var)) {
+            throw new BusinessException('参数不合法');
+        }
+        return $var;
+    }
+
+    /**
+     * 检测是否是合法Path
+     * @param $var
+     * @return string
+     * @throws BusinessException
+     */
+    public static function filterPath($var): string
+    {
+        if (!is_string($var) || !preg_match('/^[a-zA-Z0-9_\-\/]+$/', $var)) {
+            throw new BusinessException('参数不合法');
+        }
+        return $var;
+    }
+
+    /**
+     * 类转换为url path
+     * @param $controller_class
+     * @return false|string
+     */
+    static function controllerToUrlPath($controller_class)
+    {
+        $key = strtolower($controller_class);
+        $action = '';
+        if (strpos($key, '@')) {
+            [$key, $action] = explode( '@', $key, 2);
+        }
+        $prefix = 'plugin';
+        $paths = explode('\\', $key);
+        if (count($paths) < 2) {
+            return false;
+        }
+        $base = '';
+        if (strpos($key, "$prefix\\") === 0) {
+            if (count($paths) < 4) {
+                return false;
+            }
+            array_shift($paths);
+            $plugin = array_shift($paths);
+            $base = "/app/$plugin/";
+        }
+        array_shift($paths);
+        foreach ($paths as $index => $path) {
+            if ($path === 'controller') {
+                unset($paths[$index]);
+            }
+        }
+        $suffix = 'controller';
+        $code = $base . implode('/', $paths);
+        if (substr($code, -strlen($suffix)) === $suffix) {
+            $code = substr($code, 0, -strlen($suffix));
+        }
+        return $action ? "$code/$action" : $code;
+    }
+
+    /**
+     * 转换为驼峰
+     * @param string $value
+     * @return string
+     */
+    public static function camel(string $value): string
+    {
+        static $cache = [];
+        $key = $value;
+
+        if (isset($cache[$key])) {
+            return $cache[$key];
+        }
+
+        $value = ucwords(str_replace(['-', '_'], ' ', $value));
+
+        return $cache[$key] = str_replace(' ', '', $value);
+    }
+
+    /**
+     * 转换为小驼峰
+     * @param $value
+     * @return string
+     */
+    public static function smCamel($value): string
+    {
+        return lcfirst(static::camel($value));
+    }
+
+    /**
+     * 获取注释中第一行
+     * @param $comment
+     * @return false|mixed|string
+     */
+    public static function getCommentFirstLine($comment)
+    {
+        if ($comment === false) {
+            return false;
+        }
+        foreach (explode("\n", $comment) as $str) {
+            if ($s = trim($str, "*/\ \t\n\r\0\x0B")) {
+                return $s;
+            }
+        }
+        return $comment;
+    }
+
+    /**
+     * 表单类型到插件的映射
+     * @return \string[][]
+     */
+    public static function methodControlMap(): array
+    {
+        return  [
+            //method=>[控件]
+            'integer' => ['InputNumber'],
+            'string' => ['Input'],
+            'text' => ['TextArea'],
+            'date' => ['DatePicker'],
+            'enum' => ['Select'],
+            'float' => ['Input'],
+
+            'tinyInteger' => ['InputNumber'],
+            'smallInteger' => ['InputNumber'],
+            'mediumInteger' => ['InputNumber'],
+            'bigInteger' => ['InputNumber'],
+
+            'unsignedInteger' => ['InputNumber'],
+            'unsignedTinyInteger' => ['InputNumber'],
+            'unsignedSmallInteger' => ['InputNumber'],
+            'unsignedMediumInteger' => ['InputNumber'],
+            'unsignedBigInteger' => ['InputNumber'],
+
+            'decimal' => ['Input'],
+            'double' => ['Input'],
+
+            'mediumText' => ['TextArea'],
+            'longText' => ['TextArea'],
+
+            'dateTime' => ['DateTimePicker'],
+
+            'time' => ['DateTimePicker'],
+            'timestamp' => ['DateTimePicker'],
+
+            'char' => ['Input'],
+
+            'binary' => ['Input'],
+
+            'json' => ['input']
+        ];
+    }
+
+    /**
+     * 数据库类型到插件的转换
+     * @param $type
+     * @return string
+     */
+    public static function typeToControl($type): string
+    {
+        if (stripos($type, 'int') !== false) {
+            return 'inputNumber';
+        }
+        if (stripos($type, 'time') !== false || stripos($type, 'date') !== false) {
+            return 'dateTimePicker';
+        }
+        if (stripos($type, 'text') !== false) {
+            return 'textArea';
+        }
+        if ($type === 'enum') {
+            return 'select';
+        }
+        return 'input';
+    }
+
+    /**
+     * 数据库类型到表单类型的转换
+     * @param $type
+     * @param $unsigned
+     * @return string
+     */
+    public static function typeToMethod($type, $unsigned = false)
+    {
+        if (stripos($type, 'int') !== false) {
+            $type = str_replace('int', 'Integer', $type);
+            return $unsigned ? "unsigned" . ucfirst($type) : lcfirst($type);
+        }
+        $map = [
+            'int' => 'integer',
+            'varchar' => 'string',
+            'mediumtext' => 'mediumText',
+            'longtext' => 'longText',
+            'datetime' => 'dateTime',
+        ];
+        return $map[$type] ?? $type;
+    }
+
+    /**
+     * 按表获取摘要
+     * @param $table
+     * @param null $section
+     * @return array|mixed
+     * @throws BusinessException
+     */
+    public static function getSchema($table, $section = null)
+    {
+        Util::checkTableName($table);
+        $database = config('database.connections')['plugin.admin.mysql']['database'];
+        $schema_raw = $section !== 'table' ? Util::db()->select("select * from information_schema.COLUMNS where TABLE_SCHEMA = '$database' and table_name = '$table' order by ORDINAL_POSITION") : [];
+        $forms = [];
+        $columns = [];
+        foreach ($schema_raw as $item) {
+            $field = $item->COLUMN_NAME;
+            $columns[$field] = [
+                'field' => $field,
+                'type' => Util::typeToMethod($item->DATA_TYPE, (bool)strpos($item->COLUMN_TYPE, 'unsigned')),
+                'comment' => $item->COLUMN_COMMENT,
+                'default' => $item->COLUMN_DEFAULT,
+                'length' => static::getLengthValue($item),
+                'nullable' => $item->IS_NULLABLE !== 'NO',
+                'primary_key' => $item->COLUMN_KEY === 'PRI',
+                'auto_increment' => strpos($item->EXTRA, 'auto_increment') !== false
+            ];
+
+            $forms[$field] = [
+                'field' => $field,
+                'comment' => $item->COLUMN_COMMENT,
+                'control' => static::typeToControl($item->DATA_TYPE),
+                'form_show' => $item->COLUMN_KEY !== 'PRI',
+                'list_show' => true,
+                'enable_sort' => false,
+                'searchable' => false,
+                'search_type' => 'normal',
+                'control_args' => '',
+            ];
+        }
+        $table_schema = $section == 'table' || !$section ? Util::db()->select("SELECT TABLE_COMMENT FROM  information_schema.`TABLES` WHERE  TABLE_SCHEMA='$database' and TABLE_NAME='$table'") : [];
+        $indexes = !$section || in_array($section, ['keys', 'table']) ? Util::db()->select("SHOW INDEX FROM `$table`") : [];
+        $keys = [];
+        $primary_key = [];
+        foreach ($indexes as $index) {
+            $key_name = $index->Key_name;
+            if ($key_name == 'PRIMARY') {
+                $primary_key[] = $index->Column_name;
+                continue;
+            }
+            if (!isset($keys[$key_name])) {
+                $keys[$key_name] = [
+                    'name' => $key_name,
+                    'columns' => [],
+                    'type' => $index->Non_unique == 0 ? 'unique' : 'normal'
+                ];
+            }
+            $keys[$key_name]['columns'][] = $index->Column_name;
+        }
+
+        $data = [
+            'table' => ['name' => $table, 'comment' => $table_schema[0]->TABLE_COMMENT ?? '', 'primary_key' => $primary_key],
+            'columns' => $columns,
+            'forms' => $forms,
+            'keys' => array_reverse($keys, true)
+        ];
+
+        $schema = Option::where('name', "table_form_schema_$table")->value('value');
+        $form_schema_map = $schema ? json_decode($schema, true) : [];
+
+        foreach ($data['forms'] as $field => $item) {
+            if (isset($form_schema_map[$field])) {
+                $data['forms'][$field] = $form_schema_map[$field];
+            }
+        }
+
+        return $section ? $data[$section] : $data;
+    }
+
+    /**
+     * 获取字段长度或默认值
+     * @param $schema
+     * @return mixed|string
+     */
+    public static function getLengthValue($schema)
+    {
+        $type = $schema->DATA_TYPE;
+        if (in_array($type, ['float', 'decimal', 'double'])) {
+            return "{$schema->NUMERIC_PRECISION},{$schema->NUMERIC_SCALE}";
+        }
+        if ($type === 'enum') {
+            return implode(',', array_map(function($item){
+                return trim($item, "'");
+            }, explode(',', substr($schema->COLUMN_TYPE, 5, -1))));
+        }
+        if (in_array($type, ['varchar', 'text', 'char'])) {
+            return $schema->CHARACTER_MAXIMUM_LENGTH;
+        }
+        if (in_array($type, ['time', 'datetime', 'timestamp'])) {
+            return $schema->CHARACTER_MAXIMUM_LENGTH;
+        }
+        return '';
+    }
+
+    /**
+     * 获取控件参数
+     * @param $control
+     * @param $control_args
+     * @return array
+     */
+    public static function getControlProps($control, $control_args): array
+    {
+        if (!$control_args) {
+            return [];
+        }
+        $control = strtolower($control);
+        $props = [];
+        $split = explode(';', $control_args);
+        foreach ($split as $item) {
+            $pos = strpos($item, ':');
+            if ($pos === false) {
+                continue;
+            }
+            $name = trim(substr($item, 0, $pos));
+            $values = trim(substr($item, $pos + 1));
+            // values = a:v,c:d
+            $pos = strpos($values, ':');
+            if ($pos !== false && strpos($values, "#") !== 0) {
+                $options = explode(',', $values);
+                $values = [];
+                foreach ($options as $option) {
+                    [$v, $n] = explode(':', $option);
+                    if (in_array($control, ['select', 'selectmulti', 'treeselect', 'treemultiselect']) && $name == 'data') {
+                        $values[] = ['value' => $v, 'name' => $n];
+                    } else {
+                        $values[$v] = $n;
+                    }
+                }
+            }
+            $props[$name] = $values;
+        }
+        return $props;
+
+    }
+
+    /**
+     * 获取某个composer包的版本
+     * @param string $package
+     * @return mixed|string
+     */
+    public static function getPackageVersion(string $package)
+    {
+        $installed_php = base_path('vendor/composer/installed.php');
+        if (is_file($installed_php)) {
+            $packages = include $installed_php;
+        }
+        return substr($packages['versions'][$package]['version'] ?? 'unknown  ', 0, -2);
+    }
+
+
+    /**
+     * Reload webman
+     * @return bool
+     */
+    public static function reloadWebman()
+    {
+        if (function_exists('posix_kill')) {
+            try {
+                posix_kill(posix_getppid(), SIGUSR1);
+                return true;
+            } catch (Throwable $e) {}
+        } else {
+            Timer::add(1, function () {
+                Worker::stopAll();
+            });
+        }
+        return false;
+    }
+
+    /**
+     * Pause file monitor
+     * @return void
+     */
+    public static function pauseFileMonitor()
+    {
+        if (method_exists(Monitor::class, 'pause')) {
+            Monitor::pause();
+        }
+    }
+
+    /**
+     * Resume file monitor
+     * @return void
+     */
+    public static function resumeFileMonitor()
+    {
+        if (method_exists(Monitor::class, 'resume')) {
+            Monitor::resume();
+        }
+    }
+
+}

+ 260 - 0
plugin/admin/app/controller/AccountController.php

@@ -0,0 +1,260 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use plugin\admin\app\common\Auth;
+    use plugin\admin\app\common\Util;
+    use plugin\admin\app\model\Admin;
+    use support\exception\BusinessException;
+    use support\Request;
+    use support\Response;
+    use Throwable;
+    use Webman\Captcha\CaptchaBuilder;
+    use Webman\Captcha\PhraseBuilder;
+
+    /**
+     * 管理员账户
+     */
+    class AccountController extends Crud
+    {
+        /**
+         * 不需要登录的方法
+         * @var string[]
+         */
+        protected $noNeedLogin = ['login', 'logout', 'captcha'];
+
+        /**
+         * 不需要鉴权的方法
+         * @var string[]
+         */
+        protected $noNeedAuth = ['info'];
+
+        /**
+         * @var Admin
+         */
+        protected $model = null;
+
+        /**
+         * 构造函数
+         */
+        public function __construct()
+        {
+            $this->model = new Admin;
+        }
+
+        /**
+         * 账户设置
+         * @return Response
+         * @throws Throwable
+         */
+        public function index()
+        {
+            return raw_view('account/index');
+        }
+
+        /**
+         * 登录
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException
+         */
+        public function login(Request $request): Response
+        {
+            $this->checkDatabaseAvailable();
+            $captcha = $request->post('captcha', '');
+            if (strtolower($captcha) !== session('captcha-login')) {
+                return $this->json(1, '验证码错误');
+            }
+            $request->session()->forget('captcha-login');
+            $username = $request->post('username', '');
+            $password = $request->post('password', '');
+            if (!$username) {
+                return $this->json(1, '用户名不能为空');
+            }
+            $this->checkLoginLimit($username);
+            $admin = Admin::where('username', $username)->first();
+            if (!$admin || !Util::passwordVerify($password, $admin->password)) {
+                return $this->json(1, '账户不存在或密码错误');
+            }
+            if ($admin->status != 0) {
+                return $this->json(1, '当前账户暂时无法登录');
+            }
+            $admin->login_at = date('Y-m-d H:i:s');
+            $admin->save();
+            $this->removeLoginLimit($username);
+            $admin             = $admin->toArray();
+            $session           = $request->session();
+            $admin['password'] = md5($admin['password']);
+            $session->set('admin', $admin);
+            return $this->json(0, '登录成功', [
+                'nickname' => $admin['nickname'],
+                'token'    => $request->sessionId(),
+            ]);
+        }
+
+        protected function checkDatabaseAvailable()
+        {
+            if (!config('plugin.admin.database')) {
+                throw new BusinessException('请重启webman');
+            }
+        }
+
+        /**
+         * 检查登录频率限制
+         * @param $username
+         * @return void
+         * @throws BusinessException
+         */
+        protected function checkLoginLimit($username)
+        {
+            $limit_log_path = runtime_path() . '/login';
+            if (!is_dir($limit_log_path)) {
+                mkdir($limit_log_path, 0777, true);
+            }
+            $limit_file = $limit_log_path . '/' . md5($username) . '.limit';
+            $time       = date('YmdH') . ceil(date('i') / 5);
+            $limit_info = [];
+            if (is_file($limit_file)) {
+                $json_str   = file_get_contents($limit_file);
+                $limit_info = json_decode($json_str, true);
+            }
+
+            if (!$limit_info || $limit_info['time'] != $time) {
+                $limit_info = [
+                    'username' => $username,
+                    'count'    => 0,
+                    'time'     => $time
+                ];
+            }
+            $limit_info['count'] ++;
+            file_put_contents($limit_file, json_encode($limit_info));
+            if ($limit_info['count'] >= 5) {
+                throw new BusinessException('登录失败次数过多,请5分钟后再试');
+            }
+        }
+
+        /**
+         * 解除登录频率限制
+         * @param $username
+         * @return void
+         */
+        protected function removeLoginLimit($username)
+        {
+            $limit_log_path = runtime_path() . '/login';
+            $limit_file     = $limit_log_path . '/' . md5($username) . '.limit';
+            if (is_file($limit_file)) {
+                unlink($limit_file);
+            }
+        }
+
+        /**
+         * 退出
+         * @param Request $request
+         * @return Response
+         */
+        public function logout(Request $request): Response
+        {
+            $request->session()->delete('admin');
+            return $this->json(0);
+        }
+
+        /**
+         * 获取登录信息
+         * @param Request $request
+         * @return Response
+         */
+        public function info(Request $request): Response
+        {
+            $admin = admin();
+            if (!$admin) {
+                return $this->json(1);
+            }
+            $info = [
+                'id'           => $admin['id'],
+                'username'     => $admin['username'],
+                'nickname'     => $admin['nickname'],
+                'avatar'       => $admin['avatar'],
+                'email'        => $admin['email'],
+                'mobile'       => $admin['mobile'],
+                'isSuperAdmin' => Auth::isSuperAdmin(),
+                'token'        => $request->sessionId(),
+            ];
+            return $this->json(0, 'ok', $info);
+        }
+
+        /**
+         * 修改密码
+         * @param Request $request
+         * @return Response
+         */
+        public function password(Request $request): Response
+        {
+            $hash     = Admin::find(admin_id())['password'];
+            $password = $request->post('password');
+            if (!$password) {
+                return $this->json(2, '密码不能为空');
+            }
+            if ($request->post('password_confirm') !== $password) {
+                return $this->json(3, '两次密码输入不一致');
+            }
+            if (!Util::passwordVerify($request->post('old_password'), $hash)) {
+                return $this->json(1, '原始密码不正确');
+            }
+            $update_data = [
+                'password' => Util::passwordHash($password)
+            ];
+            Admin::where('id', admin_id())->update($update_data);
+            return $this->json(0);
+        }
+
+        /**
+         * 更新
+         * @param Request $request
+         * @return Response
+         */
+        public function update(Request $request): Response
+        {
+            $allow_column = [
+                'nickname' => 'nickname',
+                'avatar'   => 'avatar',
+                'email'    => 'email',
+                'mobile'   => 'mobile',
+            ];
+
+            $data        = $request->post();
+            $update_data = [];
+            foreach ($allow_column as $key => $column) {
+                if (isset($data[$key])) {
+                    $update_data[$column] = $data[$key];
+                }
+            }
+            if (isset($update_data['password'])) {
+                $update_data['password'] = Util::passwordHash($update_data['password']);
+            }
+            Admin::where('id', admin_id())->update($update_data);
+            $admin = admin();
+            unset($update_data['password']);
+            foreach ($update_data as $key => $value) {
+                $admin[$key] = $value;
+            }
+            $request->session()->set('admin', $admin);
+            return $this->json(0);
+        }
+
+        /**
+         * 验证码
+         * @param Request $request
+         * @param string $type
+         * @return Response
+         */
+        public function captcha(Request $request, string $type = 'login'): Response
+        {
+            $builder = new PhraseBuilder(4, 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ');
+            $captcha = new CaptchaBuilder(null, $builder);
+            $captcha->build(120);
+            $request->session()->set("captcha-$type", strtolower($captcha->getPhrase()));
+            $img_content = $captcha->get();
+            return response($img_content, 200, ['Content-Type' => 'image/jpeg']);
+        }
+
+    }

+ 269 - 0
plugin/admin/app/controller/AdminController.php

@@ -0,0 +1,269 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use plugin\admin\app\common\Auth;
+    use plugin\admin\app\model\Admin;
+    use plugin\admin\app\model\AdminRole;
+    use plugin\admin\app\model\User;
+    use support\exception\BusinessException;
+    use support\Request;
+    use support\Response;
+    use Throwable;
+
+    /**
+     * 管理员列表
+     */
+    class AdminController extends Crud
+    {
+        /**
+         * 不需要鉴权的方法
+         * @var array
+         */
+        protected $noNeedAuth = ['select'];
+
+        /**
+         * @var Admin
+         */
+        protected $model = null;
+
+        /**
+         * 开启auth数据限制
+         * @var string
+         */
+        protected $dataLimit = 'auth';
+
+        /**
+         * 以id为数据限制字段
+         * @var string
+         */
+        protected $dataLimitField = 'id';
+
+        /**
+         * 构造函数
+         * @return void
+         */
+        public function __construct()
+        {
+            $this->model = new Admin;
+        }
+
+        /**
+         * 浏览
+         * @return Response
+         * @throws Throwable
+         */
+        public function index(): Response
+        {
+            return raw_view('admin/index');
+        }
+
+        /**
+         * 查询
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException
+         */
+        public function select(Request $request): Response
+        {
+            [$where, $format, $limit, $field, $order] = $this->selectInput($request);
+            $query = $this->doSelect($where, $field, $order);
+            if ($format === 'select') {
+                return $this->formatSelect($query->get());
+            }
+            $paginator = $query->paginate($limit);
+            $items     = $paginator->items();
+            $admin_ids = array_column($items, 'id');
+            $roles     = AdminRole::whereIn('admin_id', $admin_ids)->get();
+            $roles_map = [];
+            foreach ($roles as $role) {
+                $roles_map[$role['admin_id']][] = $role['role_id'];
+            }
+            $login_admin_id = admin_id();
+            foreach ($items as $index => $item) {
+                $admin_id                      = $item['id'];
+                $items[$index]['roles']        = isset($roles_map[$admin_id]) ? implode(',', $roles_map[$admin_id]) : '';
+                $items[$index]['show_toolbar'] = $admin_id != $login_admin_id;
+            }
+            return json(['code' => 0, 'msg' => 'ok', 'count' => $paginator->total(), 'data' => $items]);
+        }
+
+        /**
+         * 格式化下拉列表
+         * @param $items
+         * @return Response
+         */
+        protected function formatSelect($items): Response
+        {
+            $formatted_items = [];
+            foreach ($items as $item) {
+                $formatted_items[] = [
+                    'name'  => $item->nickname,
+                    'value' => $item->id
+                ];
+            }
+            return $this->json(0, 'ok', $formatted_items);
+        }
+
+        /**
+         * 插入
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException|Throwable
+         */
+        public function insert(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+                $data = $this->insertInput($request);
+                unset($data['id']);
+                $admin_id = $this->doInsert($data);
+                $role_ids = $request->post('roles');
+                $role_ids = $role_ids ? explode(',', $role_ids) : [];
+                if (!$role_ids) {
+                    return $this->json(1, '至少选择一个角色组');
+                }
+                if (!Auth::isSuperAdmin() && array_diff($role_ids, Auth::getScopeRoleIds())) {
+                    return $this->json(1, '角色超出权限范围');
+                }
+                AdminRole::where('admin_id', $admin_id)->delete();
+                foreach ($role_ids as $id) {
+                    $admin_role           = new AdminRole;
+                    $admin_role->admin_id = $admin_id;
+                    $admin_role->role_id  = $id;
+                    $admin_role->save();
+                }
+                return $this->json(0, 'ok', ['id' => $admin_id]);
+            }
+            return raw_view('admin/insert');
+        }
+
+        /**
+         * 删除
+         * @param Request $request
+         * @return Response
+         */
+        public function delete(Request $request): Response
+        {
+            $primary_key = $this->model->getKeyName();
+            $ids         = $request->post($primary_key);
+            if (!$ids) {
+                return $this->json(0);
+            }
+            $ids = (array)$ids;
+            if (in_array(admin_id(), $ids)) {
+                return $this->json(1, '不能删除自己');
+            }
+            if (!Auth::isSuperAdmin() && array_diff($ids, Auth::getScopeAdminIds())) {
+                return $this->json(1, '无数据权限');
+            }
+            $this->model->whereIn($primary_key, $ids)->each(function (Admin $admin) {
+                $admin->delete();
+            });
+            AdminRole::whereIn('admin_id', $ids)->each(function (AdminRole $admin_role) {
+                $admin_role->delete();
+            });
+            return $this->json(0);
+        }
+
+        /**
+         * 关联团队长
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException|Throwable
+         */
+        public function relevance(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+                if (!empty($request->post('team_id'))) {
+                    Admin::query()->where('id', $request->post('id'))->update(['team_id' => $request->post('team_id')]);
+                } else {
+                    Admin::query()->where('id', $request->post('id'))->update(['team_id' => 0]);
+                }
+
+                return $this->json(0);
+            }
+
+            return raw_view('admin/relevance');
+        }
+
+        /**
+         * 更新
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException|Throwable
+         */
+        public function update(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+
+                [$id, $data] = $this->updateInput($request);
+                $admin_id = $request->post('id');
+                if (!$admin_id) {
+                    return $this->json(1, '缺少参数');
+                }
+
+                // 不能禁用自己
+                if (isset($data['status']) && $data['status'] == 1 && $id == admin_id()) {
+                    return $this->json(1, '不能禁用自己');
+                }
+
+                // 需要更新角色
+                $role_ids = $request->post('roles');
+                if ($role_ids !== null) {
+                    if (!$role_ids) {
+                        return $this->json(1, '至少选择一个角色组');
+                    }
+                    $role_ids = explode(',', $role_ids);
+
+                    $is_supper_admin = Auth::isSuperAdmin();
+                    $exist_role_ids  = AdminRole::where('admin_id', $admin_id)->pluck('role_id')->toArray();
+                    $scope_role_ids  = Auth::getScopeRoleIds();
+                    if (!$is_supper_admin && !array_intersect($exist_role_ids, $scope_role_ids)) {
+                        return $this->json(1, '无权限更改该记录');
+                    }
+                    if (!$is_supper_admin && array_diff($role_ids, $scope_role_ids)) {
+                        return $this->json(1, '角色超出权限范围');
+                    }
+
+                    // 删除账户角色
+                    $delete_ids = array_diff($exist_role_ids, $role_ids);
+                    AdminRole::whereIn('role_id', $delete_ids)->where('admin_id', $admin_id)->delete();
+                    // 添加账户角色
+                    $add_ids = array_diff($role_ids, $exist_role_ids);
+                    foreach ($add_ids as $role_id) {
+                        $admin_role           = new AdminRole;
+                        $admin_role->admin_id = $admin_id;
+                        $admin_role->role_id  = $role_id;
+                        $admin_role->save();
+                    }
+                }
+
+                $this->doUpdate($id, $data);
+                return $this->json(0);
+            }
+
+            return raw_view('admin/update');
+        }
+
+        /**
+         * 获取团队长信息
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException|Throwable
+         */
+        public function team(Request $request): Response
+        {
+            $data = User::query()->where('team_id', '>', 0)
+                ->where('is_team', 1)
+                ->selectRaw('id as value,name,mobile')->get();
+            $arr  = [['value'=>0,'name'=>'无']];
+            foreach ($data as $k => $v) {
+                $arr[] = [
+                    'value' => $v['value'],
+                    'name'  => $v['name'] . '---' . $v['mobile'],
+                ];
+            }
+            return json(['code' => 0, 'data' => $arr, 'msg' => 'ok']);
+        }
+
+    }

+ 254 - 0
plugin/admin/app/controller/ApplyRecordController.php

@@ -0,0 +1,254 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use app\api\repositories\MoneyLogRepositories;
+    use app\business\StreamBusiness;
+    use Illuminate\Support\Arr;
+    use plugin\admin\app\model\ApplyRecord;
+    use plugin\admin\app\repositories\WithdrawRepositories;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Log;
+    use support\Request;
+    use support\Response;
+    use plugin\admin\app\model\Withdraw;
+    use plugin\admin\app\controller\Crud;
+    use support\exception\BusinessException;
+
+    /**
+     * 提现列表
+     */
+    class ApplyRecordController extends Crud
+    {
+
+
+        /**
+         * @var ApplyRecord
+         */
+        protected $model = null;
+
+        /**
+         * 构造函数
+         * @return void
+         */
+        public function __construct()
+        {
+            $this->model = new ApplyRecord();
+        }
+
+        /**
+         * 浏览
+         * @return Response
+         */
+        public function index(): Response
+        {
+            return view('applyrecord/index');
+        }
+        /**
+         * 更新
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException
+         */
+        public function update(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+                return parent::update($request);
+            }
+            return view('applyrecord/update');
+        }
+
+        /**查询收银余额
+         * @param Request $request
+         * @return Response
+         */
+        public function select(Request $request): Response
+        {
+            $param = $request->all();
+            $data  = ApplyRecord::query()->where(function ($query) use ($param) {
+                if (Arr::get($param, 'created_at.0') && Arr::get($param, 'created_at.1')) {
+                    $query->whereBetween('created_at', [$param['created_at'][0], $param['created_at'][1]]);
+                } elseif (Arr::get($param, 'created_at.0')) {
+                    $query->where('created_at', '>=', $param['created_at'][0]);
+                } elseif (Arr::get($param, 'created_at.1')) {
+                    $query->where('created_at', '<=', $param['created_at'][1]);
+                }
+
+                if (Arr::get($param, 'status')) {
+                    $query->where('status', $param['status']);
+                }
+                if (Arr::get($param, 'type')) {
+                    $query->where('type', $param['type']);
+                }
+                if (Arr::get($param, 'id')) {
+                    $query->where('id', $param['id']);
+                }
+
+            })->whereExists(function ($query) use ($param) {
+                $query->from('wa_users')->whereRaw('wa_users.id=wa_apply_record.uid');
+                if (Arr::get($param, 'user_name')) {
+                    $query->where('name', 'like', '%' . $param['user_name'] . '%');
+                }
+                if (Arr::get($param, 'mobile')) {
+                    $query->where('mobile', 'like', '%' . $param['mobile'] . '%');
+                }
+            })
+                ->with('userData:id,name,mobile');
+            if (Arr::get($param, 'field')) {
+                $order = 'asc';
+                if (Arr::get($param, 'order')) {
+                    $order = 'desc';
+                }
+                $data = $data->orderBy($param['field'], $order);
+            } else {
+                $data = $data->orderByDesc('id');
+            }
+            $data = $data->paginate(Arr::get($param, 'limit', 10))->toArray();
+            $arr  = [];
+            foreach ($data['data'] as $k => $v) {
+                $arr[] = [
+                    'id'              => $v['id'],
+                    'user_name'       => $v['user_data']['name'],
+                    'user_mobile'     => $v['user_data']['mobile'],
+                    'money'           => $v['money'],
+                    'type'            => $v['type'],
+                    'name'            => $v['name'],
+                    'mobile'          => $v['mobile'],
+                    'card_number'     => $v['card_number'],
+                    'status'          => $v['status'],
+                    'created_at'      => $v['created_at'],
+                    'certificate_img' => $v['certificate_img'],
+                    'scale'           => $v['scale'],
+                    'address'         => $v['province'] . $v['address']
+                ];
+            }
+            return json(['code' => 0, 'data' => $arr, 'msg' => 'ok', 'count' => $data['total']]);
+        }
+
+        /** 批量通过
+         * @param Request $request
+         * @return Response
+         */
+        public function pass(Request $request): Response
+        {
+            try {
+                $param = $request->all();
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->ArrayType()->setName('标识'),
+                ]);
+                $applyRecordModel = ApplyRecord::query();
+                foreach ($param['id'] as $k => $v) {
+                    Db::beginTransaction();
+                    try {
+                        $system = Db::table('wa_system')->first();
+
+                        $has = (clone $applyRecordModel)->where('id', $v)->lock(true)->first();
+                        if (empty($has)) {
+                            throw new \Exception('申请数据不存在!');
+                        }
+                        if ($has->status != 1) {
+                            throw new \Exception('申请数据已经处理!');
+                        }
+                        if ($has && $has->status == 1) {
+                            StreamBusiness::addStream($has->uid, $has->money, streamType15, moldType1, moldTypefild1, $v);
+                            $has->status     = 2;
+                            $has->updated_at = date('Y-m-d H:i:s');
+                            $has->save();
+
+                        } else {
+                            throw new \Exception('已处理请不要重复提交!');
+                        }
+
+                        Db::commit();
+                    } catch (\Throwable $exception) {
+                        Db::rollBack();
+                        throw new \Exception($exception->getMessage());
+                    }
+                }
+            } catch (\Throwable $exception) {
+                return $this->fail($exception->getMessage());
+            }
+            return $this->success();
+        }
+
+        /** 批量发布
+         * @param Request $request
+         * @return Response
+         */
+        public function release(Request $request): Response
+        {
+            try {
+                $param = $request->all();
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->ArrayType()->setName('标识'),
+                ]);
+                $signRecordModel = ApplyRecord::query();
+                foreach ($param['id'] as $k => $v) {
+                    Db::beginTransaction();
+                    try {
+
+                        $has = (clone $signRecordModel)->where('id', $v)->lock(true)->first();
+                        if (empty($has)) {
+                            throw new \Exception('申请数据不存在!');
+                        }
+                        if ($has->status == 4) {
+                            throw new \Exception('申请数据已经发货!');
+                        }
+                        if ($has && $has->status == 2) {
+                            $has->status     = 4;
+                            $has->updated_at = date('Y-m-d H:i:s');
+                            $has->save();
+                        } else {
+                            throw new \Exception('已处理请不要重复提交!');
+                        }
+
+                        Db::commit();
+                    } catch (\Throwable $exception) {
+                        Db::rollBack();
+                        throw new \Exception($exception->getMessage());
+                    }
+                }
+            } catch (\Throwable $exception) {
+                return $this->fail($exception->getMessage());
+            }
+            return $this->success();
+        }
+        /** 批量驳回
+         * @param Request $request
+         * @return Response
+         */
+        public function reject(Request $request): Response
+        {
+            try {
+                $param = $request->all();
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->ArrayType()->setName('标识'),
+                ]);
+                $applyRecordModel = ApplyRecord::query();
+
+                foreach ($param['id'] as $k => $v) {
+                    Db::beginTransaction();
+                    try {
+                        $has = (clone $applyRecordModel)->where('id', $v)->lock(true)->first();
+                        if (empty($has)) {
+                            throw new \Exception('暂无数据');
+                        }
+                        if ($has->status != 1) {
+                            throw new \Exception('已被审核!');
+                        }
+                        $has->status = 3;
+                        $has->save();
+                    } catch (\Throwable $exception) {
+                        Db::rollBack();
+                        throw new \Exception($exception->getMessage());
+                    }
+                    Db::commit();
+                }
+            } catch (\Throwable $exception) {
+                return $this->fail($exception->getMessage());
+            }
+            return $this->success();
+        }
+
+    }

+ 68 - 0
plugin/admin/app/controller/ArticleController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\Article;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 文章列表
+ */
+class ArticleController extends Crud
+{
+
+    /**
+     * @var Article
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new Article;
+    }
+
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('article/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('article/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('article/update');
+    }
+
+}

+ 76 - 0
plugin/admin/app/controller/ArticleTypeController.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\ArticleType;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 文章分类 
+ */
+class ArticleTypeController extends Crud
+{
+    /**
+     * @var ArticleType
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new ArticleType;
+    }
+
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('article-type/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('article-type/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('article-type/update');
+    }
+
+    /** 文章分类
+     * @param Request $request
+     * @return Response
+     */
+    public function addselect(Request $request): Response
+    {
+        return json(['code' => 0, 'data' => ArticleType::query()->where('state',1)->selectRaw('id as value,name')->get(), 'msg' => 'ok']);
+    }
+
+}

+ 68 - 0
plugin/admin/app/controller/BankCardController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\BankCard;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 银行卡删除 
+ */
+class BankCardController extends Crud
+{
+    
+    /**
+     * @var BankCard
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new BankCard;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('bank-card/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('bank-card/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+    */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('bank-card/update');
+    }
+
+}

+ 67 - 0
plugin/admin/app/controller/Base.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Model;
+use support\Response;
+
+/**
+ * 基础控制器
+ */
+class Base
+{
+
+    /**
+     * @var Model
+     */
+    protected $model = null;
+
+    /**
+     * 无需登录及鉴权的方法
+     * @var array
+     */
+    protected $noNeedLogin = [];
+
+    /**
+     * 需要登录无需鉴权的方法
+     * @var array
+     */
+    protected $noNeedAuth = [];
+
+    /**
+     * 数据限制
+     * null 不做限制,任何管理员都可以查看该表的所有数据
+     * auth 管理员能看到自己以及自己的子管理员插入的数据
+     * personal 管理员只能看到自己插入的数据
+     * @var string
+     */
+    protected $dataLimit = null;
+
+    /**
+     * 数据限制字段
+     */
+    protected $dataLimitField = 'admin_id';
+
+    /**
+     * 返回格式化json数据
+     *
+     * @param int $code
+     * @param string $msg
+     * @param array $data
+     * @return Response
+     */
+    protected function json(int $code, string $msg = 'ok', array $data = []): Response
+    {
+        return json(['code' => $code, 'data' => $data, 'msg' => $msg]);
+    }
+
+    protected function success(string $msg = '成功', array $data = []): Response
+    {
+        return $this->json(0, $msg, $data);
+    }
+
+    protected function fail(string $msg = '失败', array $data = []): Response
+    {
+        return $this->json(1, $msg, $data);
+    }
+}

+ 85 - 0
plugin/admin/app/controller/CheckInController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use app\business\CheckInBusiness;
+use app\business\StreamBusiness;
+use Respect\Validation\Validator;
+use support\Db;
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\CheckIn;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 股权认领 
+ */
+class CheckInController extends Crud
+{
+    
+    /**
+     * @var CheckIn
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new CheckIn;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('check-in/index');
+    }
+
+    /** 通过
+     * @return Response
+     */
+    public function pass(Request $request): Response
+    {
+        $param=$request->all();
+        Db::beginTransaction();
+        try {
+            Validator::input($param,[
+                'id'                  =>    Validator::notEmpty()->setName('标识'),
+            ]);
+            CheckInBusiness::pass($param['id']);
+
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            return json(['code' => 1, 'msg' => $exception->getMessage()]);
+        }
+        Db::commit();
+        return json(['code' => 0, 'msg' => '成功']);
+    }
+
+    /** 驳回
+     * @return Response
+     */
+    public function reject(Request $request): Response
+    {
+        $param=$request->all();
+        Db::beginTransaction();
+        try {
+            Validator::input($param,[
+                'id'                  =>    Validator::notEmpty()->setName('标识'),
+            ]);
+            CheckInBusiness::reject($param['id']);
+        }catch (\Throwable $exception){
+            Db::rollBack();
+            return json(['code' => 1, 'msg' => $exception->getMessage()]);
+        }
+        Db::commit();
+        return json(['code' => 0, 'msg' => '成功']);
+    }
+
+}

+ 148 - 0
plugin/admin/app/controller/ConfigController.php

@@ -0,0 +1,148 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use plugin\admin\app\common\Util;
+use plugin\admin\app\model\Option;
+use support\exception\BusinessException;
+use support\Request;
+use support\Response;
+use Throwable;
+
+/**
+ * 系统设置
+ */
+class ConfigController extends Base
+{
+    /**
+     * 不需要验证权限的方法
+     * @var string[]
+     */
+    protected $noNeedAuth = ['get'];
+
+    /**
+     * 账户设置
+     * @return Response
+     * @throws Throwable
+     */
+    public function index(): Response
+    {
+        return raw_view('config/index');
+    }
+
+    /**
+     * 获取配置
+     * @return Response
+     */
+    public function get(): Response
+    {
+        return json($this->getByDefault());
+    }
+
+    /**
+     * 基于配置文件获取默认权限
+     * @return mixed
+     */
+    protected function getByDefault()
+    {
+        $name = 'system_config';
+        $config = Option::where('name', $name)->value('value');
+        if (empty($config)) {
+            $config = file_get_contents(base_path('plugin/admin/public/config/pear.config.json'));
+            if ($config) {
+                $option = new Option();
+                $option->name = $name;
+                $option->value = $config;
+                $option->save();
+            }
+        }
+        return json_decode($config, true);
+    }
+
+    /**
+     * 更改
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function update(Request $request): Response
+    {
+        $post = $request->post();
+        $config = $this->getByDefault();
+        $data = [];
+        foreach ($post as $section => $items) {
+            if (!isset($config[$section])) {
+                continue;
+            }
+            switch ($section) {
+                case 'logo':
+                    $data[$section]['title'] = htmlspecialchars($items['title'] ?? '');
+                    $data[$section]['image'] = Util::filterUrlPath($items['image'] ?? '');
+                    $data[$section]['icp'] = htmlspecialchars($items['icp'] ?? '');
+                    $data[$section]['beian'] = htmlspecialchars($items['beian'] ?? '');
+                    $data[$section]['footer_txt'] = htmlspecialchars($items['footer_txt'] ?? '');
+                    break;
+                case 'menu':
+                    $data[$section]['data'] = Util::filterUrlPath($items['data'] ?? '');
+                    $data[$section]['accordion'] = !empty($items['accordion']);
+                    $data[$section]['collapse'] = !empty($items['collapse']);
+                    $data[$section]['control'] = !empty($items['control']);
+                    $data[$section]['controlWidth'] = (int)($items['controlWidth'] ?? 2000);
+                    $data[$section]['select'] = (int)$items['select'] ?? 0;
+                    $data[$section]['async'] = true;
+                    break;
+                case 'tab':
+                    $data[$section]['enable'] = true;
+                    $data[$section]['keepState'] = !empty($items['keepState']);
+                    $data[$section]['preload'] = !empty($items['preload']);
+                    $data[$section]['session'] = !empty($items['session']);
+                    $data[$section]['max'] = Util::filterNum($items['max'] ?? '30');
+                    $data[$section]['index']['id'] = Util::filterNum($items['index']['id'] ?? '0');
+                    $data[$section]['index']['href'] = Util::filterUrlPath($items['index']['href'] ?? '');
+                    $data[$section]['index']['title'] = htmlspecialchars($items['index']['title'] ?? '首页');
+                    break;
+                case 'theme':
+                    $data[$section]['defaultColor'] = Util::filterNum($items['defaultColor'] ?? '2');
+                    $data[$section]['defaultMenu'] = $items['defaultMenu'] ?? '' == 'dark-theme' ?  'dark-theme' : 'light-theme';
+                    $data[$section]['defaultHeader'] = $items['defaultHeader'] ?? '' == 'dark-theme' ?  'dark-theme' : 'light-theme';
+                    $data[$section]['allowCustom'] = !empty($items['allowCustom']);
+                    $data[$section]['banner'] = !empty($items['banner']);
+                    break;
+                case 'colors':
+                    foreach ($config['colors'] as $index => $item) {
+                        if (!isset($items[$index])) {
+                            $config['colors'][$index] = $item;
+                            continue;
+                        }
+                        $data_item = $items[$index];
+                        $data[$section][$index]['id'] = $index + 1;
+                        $data[$section][$index]['color'] = $this->filterColor($data_item['color'] ?? '');
+                        $data[$section][$index]['second'] = $this->filterColor($data_item['second'] ?? '');
+                    }
+                    break;
+
+            }
+        }
+        $config = array_merge($config, $data);
+        $name = 'system_config';
+        Option::where('name', $name)->update([
+            'value' => json_encode($config)
+        ]);
+        return $this->json(0);
+    }
+
+    /**
+     * 颜色检查
+     * @param string $color
+     * @return string
+     * @throws BusinessException
+     */
+    protected function filterColor(string $color): string
+    {
+        if (!preg_match('/\#[a-zA-Z]6/', $color)) {
+            throw new BusinessException('参数错误');
+        }
+        return $color;
+    }
+
+}

+ 456 - 0
plugin/admin/app/controller/Crud.php

@@ -0,0 +1,456 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
+use Illuminate\Database\Query\Builder as QueryBuilder;
+use plugin\admin\app\common\Auth;
+use plugin\admin\app\common\Tree;
+use plugin\admin\app\common\Util;
+use support\exception\BusinessException;
+use support\Model;
+use support\Request;
+use support\Response;
+
+class Crud extends Base
+{
+
+    /**
+     * @var Model
+     */
+    protected $model = null;
+
+    /**
+     * 查询
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function select(Request $request): Response
+    {
+        [$where, $format, $limit, $field, $order] = $this->selectInput($request);
+        $query = $this->doSelect($where, $field, $order);
+        return $this->doFormat($query, $format, $limit);
+    }
+
+    /**
+     * 添加
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        $data = $this->insertInput($request);
+        $id = $this->doInsert($data);
+        return $this->json(0, 'ok', ['id' => $id]);
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function update(Request $request): Response
+    {
+        [$id, $data] = $this->updateInput($request);
+        $this->doUpdate($id, $data);
+        return $this->json(0);
+    }
+
+    /**
+     * 删除
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function delete(Request $request): Response
+    {
+        $ids = $this->deleteInput($request);
+        $this->doDelete($ids);
+        return $this->json(0);
+    }
+
+    /**
+     * 查询前置
+     * @param Request $request
+     * @return array
+     * @throws BusinessException
+     */
+    protected function selectInput(Request $request): array
+    {
+        $field = $request->get('field');
+        $order = $request->get('order', 'asc');
+        $format = $request->get('format', 'normal');
+        $limit = (int)$request->get('limit', $format === 'tree' ? 1000 : 10);
+        $limit = $limit <= 0 ? 10 : $limit;
+        $order = $order === 'asc' ? 'asc' : 'desc';
+        $where = $request->get();
+        $page = (int)$request->get('page');
+        $page = $page > 0 ? $page : 1;
+        $table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();
+
+        $allow_column = Util::db()->select("desc `$table`");
+        if (!$allow_column) {
+            throw new BusinessException('表不存在');
+        }
+        $allow_column = array_column($allow_column, 'Field', 'Field');
+        if (!in_array($field, $allow_column)) {
+            $field = null;
+        }
+        foreach ($where as $column => $value) {
+            if (
+                $value === '' || !isset($allow_column[$column]) ||
+                is_array($value) && (empty($value) || !in_array($value[0], ['null', 'not null']) && !isset($value[1]))
+            ) {
+                unset($where[$column]);
+            }
+        }
+        // 按照数据限制字段返回数据
+        if (!Auth::isSuperAdmin()) {
+            if ($this->dataLimit === 'personal') {
+                $where[$this->dataLimitField] = admin_id();
+            } elseif ($this->dataLimit === 'auth') {
+                $primary_key = $this->model->getKeyName();
+                if (!Auth::isSuperAdmin() && (!isset($where[$primary_key]) || $this->dataLimitField != $primary_key)) {
+                    $where[$this->dataLimitField] = ['in', Auth::getScopeAdminIds(true)];
+                }
+            }
+        }
+        return [$where, $format, $limit, $field, $order, $page];
+    }
+
+    /**
+     * 指定查询where条件,并没有真正的查询数据库操作
+     * @param array $where
+     * @param string|null $field
+     * @param string $order
+     * @return EloquentBuilder|QueryBuilder|Model
+     */
+    protected function doSelect(array $where, string $field = null, string $order= 'desc')
+    {
+        $model = $this->model;
+        foreach ($where as $column => $value) {
+            if (is_array($value)) {
+                if ($value[0] === 'like' || $value[0] === 'not like') {
+                    $model = $model->where($column, $value[0], "%$value[1]%");
+                } elseif (in_array($value[0], ['>', '=', '<', '<>'])) {
+                    $model = $model->where($column, $value[0], $value[1]);
+                } elseif ($value[0] == 'in' && !empty($value[1])) {
+                    $valArr = $value[1];
+                    if (is_string($value[1])) {
+                        $valArr = explode(",", trim($value[1]));
+                    }
+                    $model = $model->whereIn($column, $valArr);
+                } elseif ($value[0] == 'not in' && !empty($value[1])) {
+                    $valArr = $value[1];
+                    if (is_string($value[1])) {
+                        $valArr = explode(",", trim($value[1]));
+                    }
+                    $model = $model->whereNotIn($column, $valArr);
+                }elseif ($value[0] == 'null') {
+                    $model = $model->whereNull($column);
+                } elseif ($value[0] == 'not null') {
+                    $model = $model->whereNotNull($column);
+                } elseif ($value[0] !== '' || $value[1] !== '') {
+                    $model = $model->whereBetween($column, $value);
+                }
+            } else {
+                $model = $model->where($column, $value);
+            }
+        }
+        if ($field) {
+            $model = $model->orderBy($field, $order);
+        }
+        return $model;
+    }
+
+    /**
+     * 执行真正查询,并返回格式化数据
+     * @param $query
+     * @param $format
+     * @param $limit
+     * @return Response
+     */
+    protected function doFormat($query, $format, $limit): Response
+    {
+        $methods = [
+            'select' => 'formatSelect',
+            'tree' => 'formatTree',
+            'table_tree' => 'formatTableTree',
+            'normal' => 'formatNormal',
+        ];
+        $paginator = $query->paginate($limit);
+        $total = $paginator->total();
+        $items = $paginator->items();
+        if (method_exists($this, "afterQuery")) {
+            $items = call_user_func([$this, "afterQuery"], $items);
+        }
+        $format_function = $methods[$format] ?? 'formatNormal';
+        return call_user_func([$this, $format_function], $items, $total);
+    }
+
+    /**
+     * 插入前置方法
+     * @param Request $request
+     * @return array
+     * @throws BusinessException
+     */
+    protected function insertInput(Request $request): array
+    {
+        $data = $this->inputFilter($request->post());
+        $password_filed = 'password';
+        if (isset($data[$password_filed])) {
+            $data[$password_filed] = Util::passwordHash($data[$password_filed]);
+        }
+
+        if (!Auth::isSuperAdmin()) {
+            if ($this->dataLimit === 'personal') {
+                $data[$this->dataLimitField] = admin_id();
+            } elseif ($this->dataLimit === 'auth') {
+                if (!empty($data[$this->dataLimitField])) {
+                    $admin_id = $data[$this->dataLimitField];
+                    if (!in_array($admin_id, Auth::getScopeAdminIds(true))) {
+                        throw new BusinessException('无数据权限');
+                    }
+                } else {
+                    $data[$this->dataLimitField] = admin_id();
+                }
+            }
+        } elseif ($this->dataLimit && empty($data[$this->dataLimitField])) {
+            $data[$this->dataLimitField] = admin_id();
+        }
+        return $data;
+    }
+
+    /**
+     * 执行插入
+     * @param array $data
+     * @return mixed|null
+     */
+    protected function doInsert(array $data)
+    {
+        $primary_key = $this->model->getKeyName();
+        $model_class = get_class($this->model);
+        $model = new $model_class;
+        foreach ($data as $key => $val) {
+            $model->{$key} = $val;
+        }
+        $model->save();
+        return $primary_key ? $model->$primary_key : null;
+    }
+
+    /**
+     * 更新前置方法
+     * @param Request $request
+     * @return array
+     * @throws BusinessException
+     */
+    protected function updateInput(Request $request): array
+    {
+        $primary_key = $this->model->getKeyName();
+        $id = $request->post($primary_key);
+        $data = $this->inputFilter($request->post());
+        $model = $this->model->find($id);
+        if (!$model) {
+            throw new BusinessException('记录不存在', 2);
+        }
+
+        if (!Auth::isSuperAdmin()) {
+            if ($this->dataLimit == 'personal') {
+                if ($model->{$this->dataLimitField} != admin_id()) {
+                    throw new BusinessException('无数据权限');
+                }
+            } elseif ($this->dataLimit == 'auth') {
+                $scopeAdminIds = Auth::getScopeAdminIds(true);
+                $admin_ids = [
+                    $data[$this->dataLimitField] ?? false, // 检查要更新的数据admin_id是否是有权限的值
+                    $model->{$this->dataLimitField} ?? false // 检查要更新的记录的admin_id是否有权限
+                ];
+                foreach ($admin_ids as $admin_id) {
+                    if ($admin_id && !in_array($admin_id, $scopeAdminIds)) {
+                        throw new BusinessException('无数据权限');
+                    }
+                }
+            }
+        }
+        $password_filed = 'password';
+        if (isset($data[$password_filed])) {
+            // 密码为空,则不更新密码
+            if ($data[$password_filed] === '') {
+                unset($data[$password_filed]);
+            } else {
+                $data[$password_filed] = Util::passwordHash($data[$password_filed]);
+            }
+        }
+        unset($data[$primary_key]);
+        return [$id, $data];
+    }
+
+    /**
+     * 执行更新
+     * @param $id
+     * @param $data
+     * @return void
+     */
+    protected function doUpdate($id, $data)
+    {
+        $model = $this->model->find($id);
+        foreach ($data as $key => $val) {
+            $model->{$key} = $val;
+        }
+        $model->save();
+    }
+
+    /**
+     * 对用户输入表单过滤
+     * @param array $data
+     * @return array
+     * @throws BusinessException
+     */
+    protected function inputFilter(array $data): array
+    {
+        $table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();
+        $allow_column = $this->model->getConnection()->select("desc `$table`");
+        if (!$allow_column) {
+            throw new BusinessException('表不存在', 2);
+        }
+        $columns = array_column($allow_column, 'Type', 'Field');
+        foreach ($data as $col => $item) {
+            if (!isset($columns[$col])) {
+                unset($data[$col]);
+                continue;
+            }
+            // 非字符串类型传空则为null
+            if ($item === '' && strpos(strtolower($columns[$col]), 'varchar') === false && strpos(strtolower($columns[$col]), 'text') === false) {
+                $data[$col] = null;
+            }
+            if (is_array($item)) {
+                $data[$col] = implode(',', $item);
+            }
+        }
+        if (empty($data['created_at'])) {
+            unset($data['created_at']);
+        }
+        if (empty($data['updated_at'])) {
+            unset($data['updated_at']);
+        }
+        return $data;
+    }
+
+    /**
+     * 删除前置方法
+     * @param Request $request
+     * @return array
+     * @throws BusinessException
+     */
+    protected function deleteInput(Request $request): array
+    {
+        $primary_key = $this->model->getKeyName();
+        if (!$primary_key) {
+            throw new BusinessException('该表无主键,不支持删除');
+        }
+        $ids = (array)$request->post($primary_key, []);
+        if (!Auth::isSuperAdmin()){
+            if ($this->dataLimit) {
+                $admin_ids = $this->model->where($primary_key, $ids)->pluck($this->dataLimitField)->toArray();
+            }
+            if ($this->dataLimit == 'personal') {
+                if (!in_array(admin_id(), $admin_ids)) {
+                    throw new BusinessException('无数据权限');
+                }
+            } elseif ($this->dataLimit == 'auth') {
+                if (array_diff($admin_ids, Auth::getScopeAdminIds(true))) {
+                    throw new BusinessException('无数据权限');
+                }
+            }
+        }
+        return $ids;
+    }
+
+    /**
+     * 执行删除
+     * @param array $ids
+     * @return void
+     */
+    protected function doDelete(array $ids)
+    {
+        if (!$ids) {
+            return;
+        }
+        $primary_key = $this->model->getKeyName();
+        $this->model->whereIn($primary_key, $ids)->each(function ($model) {
+            $model->delete();
+        });
+    }
+
+    /**
+     * 格式化树
+     * @param $items
+     * @return Response
+     */
+    protected function formatTree($items): Response
+    {
+        $format_items = [];
+        foreach ($items as $item) {
+            $format_items[] = [
+                'name' => $item->title ?? $item->name ?? $item->id,
+                'value' => (string)$item->id,
+                'id' => $item->id,
+                'pid' => $item->pid,
+            ];
+        }
+        $tree = new Tree($format_items);
+        return $this->json(0, 'ok', $tree->getTree());
+    }
+
+    /**
+     * 格式化表格树
+     * @param $items
+     * @return Response
+     */
+    protected function formatTableTree($items): Response
+    {
+        $tree = new Tree($items);
+        return $this->json(0, 'ok', $tree->getTree());
+    }
+
+    /**
+     * 格式化下拉列表
+     * @param $items
+     * @return Response
+     */
+    protected function formatSelect($items): Response
+    {
+        $formatted_items = [];
+        foreach ($items as $item) {
+            $formatted_items[] = [
+                'name' => $item->title ?? $item->name ?? $item->id,
+                'value' => $item->id
+            ];
+        }
+        return  $this->json(0, 'ok', $formatted_items);
+    }
+
+    /**
+     * 通用格式化
+     * @param $items
+     * @param $total
+     * @return Response
+     */
+    protected function formatNormal($items, $total): Response
+    {
+        return json(['code' => 0, 'msg' => 'ok', 'count' => $total, 'data' => $items]);
+    }
+
+    /**
+     * 查询数据库后置方法,可用于修改数据
+     * @param mixed $items 原数据
+     * @return mixed 修改后数据
+     */
+    protected function afterQuery($items)
+    {
+        return $items;
+    }
+}

+ 24 - 0
plugin/admin/app/controller/DevController.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use Throwable;
+
+/**
+ * 开发辅助相关
+ */
+class DevController
+{
+    /**
+     * 表单构建
+     * @return Response
+     * @throws Throwable
+     */
+    public function formBuild()
+    {
+        return raw_view('dev/form-build');
+    }
+
+}

+ 111 - 0
plugin/admin/app/controller/DictController.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use plugin\admin\app\model\Dict;
+use plugin\admin\app\model\Option;
+use support\exception\BusinessException;
+use support\Request;
+use support\Response;
+use Throwable;
+
+/**
+ * 字典管理 
+ */
+class DictController extends Base
+{
+    /**
+     * 不需要授权的方法
+     */
+    protected $noNeedAuth = ['get'];
+
+    /**
+     * 浏览
+     * @return Response
+     * @throws Throwable
+     */
+    public function index(): Response
+    {
+        return raw_view('dict/index');
+    }
+
+    /**
+     * 查询
+     * @param Request $request
+     * @return Response
+     */
+    public function select(Request $request): Response
+    {
+        $name = $request->get('name', '');
+        if ($name && is_string($name)) {
+            $items = Option::where('name', 'like', "dict_$name%")->get()->toArray();
+        } else {
+            $items = Option::where('name', 'like', 'dict_%')->get()->toArray();
+        }
+        foreach ($items as &$item) {
+            $item['name'] = Dict::optionNameTodictName($item['name']);
+        }
+        return $this->json(0, 'ok', $items);
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException|Throwable
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            $name = $request->post('name');
+            if (Dict::get($name)) {
+                return $this->json(1, '字典已经存在');
+            }
+            $values = (array)$request->post('value', []);
+            Dict::save($name, $values);
+        }
+        return raw_view('dict/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException|Throwable
+     */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            $name = $request->post('name');
+            if (!Dict::get($name)) {
+                return $this->json(1, '字典不存在');
+            }
+            Dict::save($name, $request->post('value'));
+        }
+        return raw_view('dict/update');
+    }
+
+    /**
+     * 删除
+     * @param Request $request
+     * @return Response
+     */
+    public function delete(Request $request): Response
+    {
+        $names = (array)$request->post('name');
+        Dict::delete($names);
+        return $this->json(0);
+    }
+
+    /**
+     * 获取
+     * @param Request $request
+     * @param $name
+     * @return Response
+     */
+    public function get(Request $request, $name): Response
+    {
+        return $this->json(0, 'ok', (array)Dict::get($name));
+    }
+
+}

+ 85 - 0
plugin/admin/app/controller/GoodController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\Good;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 产品列表 
+ */
+class GoodController extends Crud
+{
+    
+    /**
+     * @var Good
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new Good;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('good/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('good/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+    */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('good/update');
+    }
+
+    /** 产品下拉选择
+     * @param Request $request
+     * @return Response
+     */
+    public function addselect(Request $request): Response
+    {
+        $data=Good::query()->where('type',3)->selectRaw('id as value,name,type')->get()->toArray();
+        $arr=[];
+        foreach ($data as $k=>$v){
+            $arr[]=[
+                'value'=>$v['value'],
+                'name'=>$v['name'],
+            ];
+        }
+        return json(['code' => 0, 'data' =>$arr, 'msg' => 'ok']);
+    }
+
+}

+ 202 - 0
plugin/admin/app/controller/IndexController.php

@@ -0,0 +1,202 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use plugin\admin\app\common\Util;
+    use plugin\admin\app\model\Option;
+    use plugin\admin\app\model\Payorder;
+    use plugin\admin\app\model\Sign;
+    use plugin\admin\app\model\Stream;
+    use plugin\admin\app\model\User;
+    use plugin\admin\app\model\Withdraw;
+    use support\exception\BusinessException;
+    use support\Request;
+    use support\Response;
+    use think\db\Where;
+    use Throwable;
+    use Workerman\Worker;
+
+    class IndexController
+    {
+
+        /**
+         * 无需登录的方法
+         * @var string[]
+         */
+        protected $noNeedLogin = ['index'];
+
+        /**
+         * 不需要鉴权的方法
+         * @var string[]
+         */
+        protected $noNeedAuth = ['dashboard'];
+
+        /**
+         * 后台主页
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException|Throwable
+         */
+        public function index(Request $request): Response
+        {
+            clearstatcache();
+            if (!is_file(base_path('plugin/admin/config/database.php'))) {
+                return raw_view('index/install');
+            }
+            $admin = admin();
+            if (!$admin) {
+                $name   = 'system_config';
+                $config = Option::where('name', $name)->value('value');
+                $config = json_decode($config, true);
+                $title  = $config['logo']['title'] ?? 'webman admin';
+                $logo   = $config['logo']['image'] ?? '/app/admin/admin/images/logo.png';
+                return raw_view('account/login', ['logo' => $logo, 'title' => $title]);
+            }
+            return raw_view('index/index');
+        }
+
+        /**
+         * 仪表板
+         * @param Request $request
+         * @return Response
+         * @throws Throwable
+         */
+        public function dashboard(Request $request): Response
+        {
+
+            $teamId = admin('team_id');
+            $data   = Payorder::query()
+                ->where('is_pay', 2)
+                ->whereExists(function ($query) use ($teamId) {
+                    $query->from('wa_users')->whereRaw('wa_users.id=wa_payorder.user_id');
+                    if (!empty($teamId)) {
+
+                        $query->where('team_id', $teamId);
+                    }
+                })
+                ->select(['user_id', 'created_at', 'goods_type'])
+                ->get()
+                ->toArray();
+            /** @var  $user_id 获取今日购买订单信息 */
+            $user_id = collect($data)->where('created_at', '>=', date('Y-m-d') . ' 00:00:00')->pluck('user_id')->toArray();
+            $cja     = collect($data)->where('created_at', '<', date('Y-m-d') . ' 00:00:00')->whereIn('user_id', $user_id)->pluck('user_id')->toArray();
+            $numDya  = count(array_unique($user_id)) - count(array_unique($cja));
+            /** @var  $num 购买总人数 */
+            $num = collect($data)->groupBy('user_id')->count();
+
+
+            $myGoodModel = Payorder::query()
+                ->where('is_pay', 2)
+                ->where('created_at','>=', '2025-10-07 23:59:59')
+                ->whereExists(function ($query) use ($teamId) {
+                $query->from('wa_users')->whereRaw('wa_users.id=wa_payorder.user_id');
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            });
+
+            $withdrawModel = Withdraw::query()->where('status', 3)->whereExists(function ($query) use ($teamId) {
+                $query->from('wa_users')->whereRaw('wa_users.id=wa_withdraw.user_id');
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            });
+            if ($request->isAjax()) {
+                $time  = strtotime(date('Y-m-d') . ' 23:59:59');
+                $arr   = [
+                    date('Y-m-d', $time - 6 * 24 * 60 * 60),
+                    date('Y-m-d', $time - 5 * 24 * 60 * 60),
+                    date('Y-m-d', $time - 4 * 24 * 60 * 60),
+                    date('Y-m-d', $time - 3 * 24 * 60 * 60),
+                    date('Y-m-d', $time - 2 * 24 * 60 * 60),
+                    date('Y-m-d', $time - 1 * 24 * 60 * 60),
+                    date('Y-m-d', $time),
+                ];
+                $array = [];
+                foreach ($arr as $v) {
+                    $array[] = [
+                        'name'   => date('m月d日', strtotime($v)),
+                        'value1' => (clone $myGoodModel)->whereBetween('created_at', [$v . ' 00:00:00', $v . ' 23:59:59'])->sum('money'),
+                        'value2' => (clone $withdrawModel)->whereBetween('updated_at', [$v . ' 00:00:00', $v . ' 23:59:59'])->sum('money'),
+                    ];
+                }
+                return adminsuccess($array);
+            }
+            // 总用户数
+            $user_count = User::query()->where(function ($query) use ($teamId) {
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            })->count();
+            // 今日签到
+            $day7_user_count = Stream::query()
+                ->whereExists(function ($query) use ($teamId) {
+                    $query->from('wa_users')->whereRaw('wa_users.id=wa_stream.user_id');
+                    if (!empty($teamId)) {
+                        $query->where('team_id', $teamId);
+                    }
+                })->where('type', streamType2)
+                ->whereBetween('created_at', [date('Y-m-d') . ' 00:00:00', date('Y-m-d') . ' 23:59:59'])
+                ->count();
+
+            // 在线用户
+            $today_user_count = User::where('last_login', '>', time())->where(function ($query) use ($teamId) {
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            })->count();
+
+            //今日注册人数
+            $register_num = User::whereBetween('created_at',[date('Y-m-d').' 00:00:00',date('Y-m-d').' 23:59:59'])->where(function ($query) use ($teamId) {
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            })->count();
+
+
+            // 订单金额
+            $day30_user_count = Payorder::where('is_pay', 2)
+                ->where('created_at','>=', '2025-10-07 23:59:59')
+                ->whereExists(function ($query) use ($teamId) {
+                $query->from('wa_users')->whereRaw('wa_users.id=wa_payorder.user_id');
+                if (!empty($teamId)) {
+                    $query->where('team_id', $teamId);
+                }
+            })
+                ->sum('money');
+            $day7_detail      = [];
+            $now              = time();
+            for ($i = 0; $i < 7; $i ++) {
+                $date                          = date('Y-m-d', $now - 24 * 60 * 60 * $i);
+                $day7_detail[substr($date, 5)] = User::query()->where(function ($query) use ($teamId) {
+                    if (!empty($teamId)) {
+                        $query->where('team_id', $teamId);
+                    }
+                })->whereBetween('created_at', ["$date 00:00:00", "$date 23:59:59"])->count();
+            }
+
+            /** 新增购买 */
+
+            /** 总购买数 */
+
+
+            return raw_view('index/dashboard', [
+                'today_user_count' => $today_user_count,
+                'day7_user_count'  => $day7_user_count,
+                'day30_user_count' => $day30_user_count,
+                'user_count'       => $user_count,
+                'day7_detail'      => array_reverse($day7_detail),
+                'tal_num'          => $num,
+                'numDya'           => $numDya,
+                'register_num'=>$register_num,
+                /*    'two_withdraw'=>(clone $withdrawModel)->sum('money'),*/
+                'app'              => User::where('is_app', 1)->where(function ($query) use ($teamId) {
+                    if (!empty($teamId)) {
+                        $query->where('team_id', $teamId);
+                    }
+                })->count()
+
+            ]);
+        }
+
+    }

+ 392 - 0
plugin/admin/app/controller/InstallController.php

@@ -0,0 +1,392 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use Illuminate\Database\Capsule\Manager;
+use plugin\admin\app\common\Util;
+use plugin\admin\app\model\Admin;
+use support\exception\BusinessException;
+use support\Request;
+use support\Response;
+use Webman\Captcha\CaptchaBuilder;
+
+/**
+ * 安装
+ */
+class InstallController extends Base
+{
+    /**
+     * 不需要登录的方法
+     * @var string[]
+     */
+    protected $noNeedLogin = ['step1', 'step2'];
+
+    /**
+     * 设置数据库
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException|\Throwable
+     */
+    public function step1(Request $request): Response
+    {
+        $database_config_file = base_path() . '/plugin/admin/config/database.php';
+        clearstatcache();
+        if (is_file($database_config_file)) {
+            return $this->json(1, '管理后台已经安装!如需重新安装,请删除该插件数据库配置文件并重启');
+        }
+
+        if (!class_exists(CaptchaBuilder::class) || !class_exists(Manager::class)) {
+            return $this->json(1, '请运行 composer require -W illuminate/database 安装illuminate/database组件并重启');
+        }
+
+        $user = $request->post('user');
+        $password = $request->post('password');
+        $database = $request->post('database');
+        $host = $request->post('host');
+        $port = (int)$request->post('port') ?: 3306;
+        $overwrite = $request->post('overwrite');
+
+        try {
+            $db = $this->getPdo($host, $user, $password, $port);
+            $smt = $db->query("show databases like '$database'");
+            if (empty($smt->fetchAll())) {
+                $db->exec("create database $database");
+            }
+            $db->exec("use $database");
+            $smt = $db->query("show tables");
+            $tables = $smt->fetchAll();
+        } catch (\Throwable $e) {
+            if (stripos($e, 'Access denied for user')) {
+                return $this->json(1, '数据库用户名或密码错误');
+            }
+            if (stripos($e, 'Connection refused')) {
+                return $this->json(1, 'Connection refused. 请确认数据库IP端口是否正确,数据库已经启动');
+            }
+            if (stripos($e, 'timed out')) {
+                return $this->json(1, '数据库连接超时,请确认数据库IP端口是否正确,安全组及防火墙已经放行端口');
+            }
+            throw $e;
+        }
+
+        $tables_to_install = [
+            'wa_admins',
+            'wa_admin_roles',
+            'wa_roles',
+            'wa_rules',
+            'wa_options',
+            'wa_users',
+            'wa_uploads',
+        ];
+
+        $tables_exist = [];
+        foreach ($tables as $table) {
+            $tables_exist[] = current($table);
+        }
+        $tables_conflict = array_intersect($tables_to_install, $tables_exist);
+        if (!$overwrite) {
+            if ($tables_conflict) {
+                return $this->json(1, '以下表' . implode(',', $tables_conflict) . '已经存在,如需覆盖请选择强制覆盖');
+            }
+        } else {
+            foreach ($tables_conflict as $table) {
+                $db->exec("DROP TABLE `$table`");
+            }
+        }
+
+        $sql_file = base_path() . '/plugin/admin/install.sql';
+        if (!is_file($sql_file)) {
+            return $this->json(1, '数据库SQL文件不存在');
+        }
+
+        $sql_query = file_get_contents($sql_file);
+        $sql_query = $this->removeComments($sql_query);
+        $sql_query = $this->splitSqlFile($sql_query, ';');
+        foreach ($sql_query as $sql) {
+            $db->exec($sql);
+        }
+
+        // 导入菜单
+        $menus = include base_path() . '/plugin/admin/config/menu.php';
+        // 安装过程中没有数据库配置,无法使用api\Menu::import()方法
+        $this->importMenu($menus, $db);
+
+        $config_content = <<<EOF
+<?php
+return  [
+    'default' => 'mysql',
+    'connections' => [
+        'mysql' => [
+            'driver'      => 'mysql',
+            'host'        => '$host',
+            'port'        => '$port',
+            'database'    => '$database',
+            'username'    => '$user',
+            'password'    => '$password',
+            'charset'     => 'utf8mb4',
+            'collation'   => 'utf8mb4_general_ci',
+            'prefix'      => '',
+            'strict'      => true,
+            'engine'      => null,
+        ],
+    ],
+];
+EOF;
+
+        file_put_contents($database_config_file, $config_content);
+
+        $think_orm_config = <<<EOF
+<?php
+return [
+    'default' => 'mysql',
+    'connections' => [
+        'mysql' => [
+            // 数据库类型
+            'type' => 'mysql',
+            // 服务器地址
+            'hostname' => '$host',
+            // 数据库名
+            'database' => '$database',
+            // 数据库用户名
+            'username' => '$user',
+            // 数据库密码
+            'password' => '$password',
+            // 数据库连接端口
+            'hostport' => $port,
+            // 数据库连接参数
+            'params' => [
+                // 连接超时3秒
+                \PDO::ATTR_TIMEOUT => 3,
+            ],
+            // 数据库编码默认采用utf8
+            'charset' => 'utf8mb4',
+            // 数据库表前缀
+            'prefix' => '',
+            // 断线重连
+            'break_reconnect' => true,
+            // 关闭SQL监听日志
+            'trigger_sql' => true,
+            // 自定义分页类
+            'bootstrap' =>  ''
+        ],
+    ],
+];
+EOF;
+        file_put_contents(base_path() . '/plugin/admin/config/thinkorm.php', $think_orm_config);
+
+
+        // 尝试reload
+        if (function_exists('posix_kill')) {
+            set_error_handler(function () {});
+            posix_kill(posix_getppid(), SIGUSR1);
+            restore_error_handler();
+        }
+
+        return $this->json(0);
+    }
+
+    /**
+     * 设置管理员
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function step2(Request $request): Response
+    {
+        $username = $request->post('username');
+        $password = $request->post('password');
+        $password_confirm = $request->post('password_confirm');
+        if ($password != $password_confirm) {
+            return $this->json(1, '两次密码不一致');
+        }
+        if (!is_file($config_file = base_path() . '/plugin/admin/config/database.php')) {
+            return $this->json(1, '请先完成第一步数据库配置');
+        }
+        $config = include $config_file;
+        $connection = $config['connections']['mysql'];
+        $pdo = $this->getPdo($connection['host'], $connection['username'], $connection['password'], $connection['port'], $connection['database']);
+
+        if ($pdo->query('select * from `wa_admins`')->fetchAll()) {
+            return $this->json(1, '后台已经安装完毕,无法通过此页面创建管理员');
+        }
+
+        $smt = $pdo->prepare("insert into `wa_admins` (`username`, `password`, `nickname`, `created_at`, `updated_at`) values (:username, :password, :nickname, :created_at, :updated_at)");
+        $time = date('Y-m-d H:i:s');
+        $data = [
+            'username' => $username,
+            'password' => Util::passwordHash($password),
+            'nickname' => '超级管理员',
+            'created_at' => $time,
+            'updated_at' => $time
+        ];
+        foreach ($data as $key => $value) {
+            $smt->bindValue($key, $value);
+        }
+        $smt->execute();
+        $admin_id = $pdo->lastInsertId();
+
+        $smt = $pdo->prepare("insert into `wa_admin_roles` (`role_id`, `admin_id`) values (:role_id, :admin_id)");
+        $smt->bindValue('role_id', 1);
+        $smt->bindValue('admin_id', $admin_id);
+        $smt->execute();
+
+        $request->session()->flush();
+        return $this->json(0);
+    }
+
+    /**
+     * 添加菜单
+     * @param array $menu
+     * @param \PDO $pdo
+     * @return int
+     */
+    protected function addMenu(array $menu, \PDO $pdo): int
+    {
+        $allow_columns = ['title', 'key', 'icon', 'href', 'pid', 'weight', 'type'];
+        $data = [];
+        foreach ($allow_columns as $column) {
+            if (isset($menu[$column])) {
+                $data[$column] = $menu[$column];
+            }
+        }
+        $time = date('Y-m-d H:i:s');
+        $data['created_at'] = $data['updated_at'] = $time;
+        $values = [];
+        foreach ($data as $k => $v) {
+            $values[] = ":$k";
+        }
+        $columns = array_keys($data);
+        foreach ($columns as $k => $column) {
+            $columns[$k] = "`$column`";
+        }
+        $sql = "insert into wa_rules (" .implode(',', $columns). ") values (" . implode(',', $values) . ")";
+        $smt = $pdo->prepare($sql);
+        foreach ($data as $key => $value) {
+            $smt->bindValue($key, $value);
+        }
+        $smt->execute();
+        return $pdo->lastInsertId();
+    }
+
+    /**
+     * 导入菜单
+     * @param array $menu_tree
+     * @param \PDO $pdo
+     * @return void
+     */
+    protected function importMenu(array $menu_tree, \PDO $pdo)
+    {
+        if (is_numeric(key($menu_tree)) && !isset($menu_tree['key'])) {
+            foreach ($menu_tree as $item) {
+                $this->importMenu($item, $pdo);
+            }
+            return;
+        }
+        $children = $menu_tree['children'] ?? [];
+        unset($menu_tree['children']);
+        $smt = $pdo->prepare("select * from wa_rules where `key`=:key limit 1");
+        $smt->execute(['key' => $menu_tree['key']]);
+        $old_menu = $smt->fetch();
+        if ($old_menu) {
+            $pid = $old_menu['id'];
+            $params = [
+                'title' => $menu_tree['title'],
+                'icon' => $menu_tree['icon'] ?? '',
+                'key' => $menu_tree['key'],
+            ];
+            $sql = "update wa_rules set title=:title, icon=:icon where `key`=:key";
+            $smt = $pdo->prepare($sql);
+            $smt->execute($params);
+        } else {
+            $pid = $this->addMenu($menu_tree, $pdo);
+        }
+        foreach ($children as $menu) {
+            $menu['pid'] = $pid;
+            $this->importMenu($menu, $pdo);
+        }
+    }
+
+    /**
+     * 去除sql文件中的注释
+     * @param $sql
+     * @return string
+     */
+    protected function removeComments($sql): string
+    {
+        return preg_replace("/(\n--[^\n]*)/","", $sql);
+    }
+
+    /**
+     * 分割sql文件
+     * @param $sql
+     * @param $delimiter
+     * @return array
+     */
+    function splitSqlFile($sql, $delimiter): array
+    {
+        $tokens = explode($delimiter, $sql);
+        $output = array();
+        $matches = array();
+        $token_count = count($tokens);
+        for ($i = 0; $i < $token_count; $i++) {
+            if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0))) {
+                $total_quotes = preg_match_all("/'/", $tokens[$i], $matches);
+                $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$i], $matches);
+                $unescaped_quotes = $total_quotes - $escaped_quotes;
+
+                if (($unescaped_quotes % 2) == 0) {
+                    $output[] = $tokens[$i];
+                    $tokens[$i] = "";
+                } else {
+                    $temp = $tokens[$i] . $delimiter;
+                    $tokens[$i] = "";
+
+                    $complete_stmt = false;
+                    for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++) {
+                        $total_quotes = preg_match_all("/'/", $tokens[$j], $matches);
+                        $escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $tokens[$j], $matches);
+                        $unescaped_quotes = $total_quotes - $escaped_quotes;
+                        if (($unescaped_quotes % 2) == 1) {
+                            $output[] = $temp . $tokens[$j];
+                            $tokens[$j] = "";
+                            $temp = "";
+                            $complete_stmt = true;
+                            $i = $j;
+                        } else {
+                            $temp .= $tokens[$j] . $delimiter;
+                            $tokens[$j] = "";
+                        }
+
+                    }
+                }
+            }
+        }
+
+        return $output;
+    }
+
+    /**
+     * 获取pdo连接
+     * @param $host
+     * @param $username
+     * @param $password
+     * @param $port
+     * @param $database
+     * @return \PDO
+     */
+    protected function getPdo($host, $username, $password, $port, $database = null): \PDO
+    {
+        $dsn = "mysql:host=$host;port=$port;";
+        if ($database) {
+            $dsn .= "dbname=$database";
+        }
+        $params = [
+            \PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8mb4",
+            \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
+            \PDO::ATTR_EMULATE_PREPARES => false,
+            \PDO::ATTR_TIMEOUT => 5,
+            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+        ];
+        return new \PDO($dsn, $username, $password, $params);
+    }
+
+}

+ 68 - 0
plugin/admin/app/controller/InviteController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\Invite;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 邀请规则 
+ */
+class InviteController extends Crud
+{
+    
+    /**
+     * @var Invite
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new Invite;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('invite/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('invite/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+    */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('invite/update');
+    }
+
+}

+ 243 - 0
plugin/admin/app/controller/MyGoodController.php

@@ -0,0 +1,243 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use app\api\repositories\PayRepositories;
+    use app\business\GoodsBusiness;
+    use app\business\PayorderBusiness;
+    use Illuminate\Support\Arr;
+    use plugin\admin\app\model\Good;
+    use plugin\admin\app\model\Payorder;
+    use plugin\admin\app\model\User;
+    use plugin\admin\app\model\Withdraw;
+    use plugin\admin\app\repositories\WithdrawRepositories;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Log;
+    use support\Request;
+    use support\Response;
+    use plugin\admin\app\model\MyGood;
+    use plugin\admin\app\controller\Crud;
+    use support\exception\BusinessException;
+
+    /**
+     * 会员产品
+     */
+    class MyGoodController extends Crud
+    {
+        /**
+         * @var MyGood
+         */
+        protected $model = null;
+
+        /**
+         * 构造函数
+         * @return void
+         */
+        public function __construct()
+        {
+            $this->model = new MyGood;
+        }
+
+        /**
+         * 浏览
+         * @return Response
+         */
+        public function index(): Response
+        {
+            return view('my-good/index');
+        }
+
+        /**手动购买
+         * @param Request $request
+         * @return Response
+         */
+        public function insert(Request $request): Response
+        {
+            if ($request->isAjax()) {
+                $param = $request->all();
+                Db::beginTransaction();
+                try {
+                    $userData = User::query()->where('mobile', $param['mobile'])->first();
+                    if (empty($userData)) {
+                        throw new \Exception('会员不存在');
+                    }
+                    $goodsData = Good::query()->where('id', $param['goods_id'])->first();
+                    if (empty($goodsData)) {
+                        throw new \Exception('产品不存在');
+                    }
+                    $payorderId = PayorderBusiness::orderAdd([
+                        'id'                 => $param['goods_id'],
+                        'pay_characteristic' => 99999,
+                        'user_data'          => [
+                            'id' => $userData->id
+                        ],
+                        'num'                => 1,
+                    ]);
+                    $payorder   = Db::table('wa_payorder')->where('id', $payorderId)->first();
+                    PayorderBusiness::payorderSave(collect($payorder)->toArray());
+                } catch (\Throwable $exception) {
+                    Db::rollBack();
+                    return $this->fail($exception->getMessage());
+                }
+                Db::commit();
+                return $this->success();
+            }
+            return view('my-good/insert');
+        }
+
+        public function select(Request $request): Response
+        {
+            $param = $request->all();
+
+            $data = MyGood::query()->where(function ($query) use ($param) {
+                if (is_numeric(Arr::get($param, 'money.1')) && is_numeric(Arr::get($param, 'money.0'))) {
+                    $query->whereBetween('money', [$param['money'][0], $param['money'][1]]);
+                } elseif (is_numeric(Arr::get($param, 'money.0'))) {
+                    $query->where('money', '>=', $param['money'][0]);
+                } elseif (is_numeric(Arr::get($param, 'money.1'))) {
+                    $query->where('money', '<=', $param['money'][1]);
+                }
+
+                if (Arr::get($param, 'created_at.0') && Arr::get($param, 'created_at.1')) {
+                    $query->whereBetween('created_at', [$param['created_at'][0], $param['created_at'][1]]);
+                } elseif (Arr::get($param, 'created_at.0')) {
+                    $query->where('created_at', '>=', $param['created_at'][0]);
+                } elseif (Arr::get($param, 'created_at.1')) {
+                    $query->where('created_at', '<=', $param['created_at'][1]);
+                }
+
+
+//            if(Arr::get($param,'rebate.0') &&  Arr::get($param,'rebate.1')){
+//                $query->whereBetween('bonus',[$param['rebate'][0],$param['rebate'][1]]);
+//            }elseif (Arr::get($param,'rebate.0')){
+//                $query->where('bonus','>=',$param['rebate'][0]);
+//            }elseif (Arr::get($param,'rebate.1')){
+//                $query->where('bonus','<=',$param['rebate'][1]);
+//            }
+            })->with('userData:id,name,mobile')
+                ->whereExists(function ($query) use ($param) {
+                    $query->from('wa_users')->whereRaw('wa_users.id=wa_my_goods.user_id');
+                    if (Arr::get($param, 'user_name')) {
+                        $query->where('name', 'like', '%' . $param['user_name'] . '%');
+                    }
+                    if (Arr::get($param, 'user_mobile')) {
+                        $query->where('mobile', 'like', '%' . $param['user_mobile'] . '%');
+                    }
+                });
+
+
+            if (Arr::get($param, 'field')) {
+                $order = 'asc';
+                if (Arr::get($param, 'order')) {
+                    $order = 'desc';
+                }
+                $data = $data->orderBy($param['field'], $order);
+            } else {
+                $data = $data->orderByDesc('id');
+            }
+            $data = $data->paginate(Arr::get($param, 'limit', 10))->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]['user_name']   = Arr::get($v['user_data'], 'name');
+                $data['data'][$k]['user_mobile'] = Arr::get($v['user_data'], 'mobile');
+                if($v['status']==1){
+                    $data['data'][$k]['status_name'] = '等待邮寄';
+                }elseif ($v['status']==2){
+                    $data['data'][$k]['status_name'] = '已发货';
+                }elseif ($v['status']==2){
+                    $data['data'][$k]['status_name'] = '已发货';
+                }else{
+                    $data['data'][$k]['status_name'] = '已发货';
+                }
+            }
+
+            return json(['code' => 0, 'data' => $data['data'], 'msg' => 'ok', 'count' => $data['total']]);
+        }
+
+        /**更换产品
+         * @param Request $request
+         * @return Response
+         */
+        public function edit_shop(Request $request): Response
+        {
+            if ($request->isAjax()) {
+                $param = $request->all();
+
+                Db::beginTransaction();
+                try {
+                    Validator::input($param, [
+                        'id'         => Validator::notEmpty()->setName('非法操作'),
+                        'goods_id'   => Validator::notEmpty()->setName('非法操作,识别码2'),
+                        'redemption' => Validator::notEmpty()->setName('换购产品'),
+                    ]);
+                    if ($param['goods_id'] == $param['redemption']) {
+                        throw new \Exception('换购产品和当前产品一致,请更换需要换购的产品!');
+                    }
+                    $data = MyGood::query()->where('id', $param['id'])->first();
+                    if (empty($data)) {
+                        throw new \Exception('当前订单不存在!');
+                    }
+                    $goodsData = Good::query()->where('id', $param['redemption'])->first();
+                    if (empty($goodsData)) {
+                        throw new \Exception('更换产品不存在!');
+                    }
+                    MyGood::query()->where('id', $param['id'])->update([
+                        'goods_id'   => $param['redemption'],
+                        'o_goods_id' => $param['goods_id'],
+                    ]);
+                } catch (\Throwable $exception) {
+                    Db::rollBack();
+                    return $this->fail($exception->getMessage());
+                }
+                Db::commit();
+                return $this->success();
+            }
+            return view('my-good/edit_shop');
+        }
+
+        /** 批量通过
+         * @param Request $request
+         * @return Response
+         */
+        public function pass(Request $request): Response
+        {
+            try {
+                $param = $request->all();
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->ArrayType()->setName('标识'),
+                ]);
+                $withdrawModel = MyGood::query();
+                foreach ($param['id'] as $k => $v) {
+                    Db::beginTransaction();
+                    try {
+                        $has = (clone $withdrawModel)->where('id', $v)->lock(true)->first();
+                        if (empty($has)) {
+                            throw new \Exception('编码为:【' . $v . '】订单不存在!');
+                        }
+                        if ($has->status != 1) {
+                            throw new \Exception('编码为:【' . $v . '】已处理请不要重复提交!');
+                        }
+
+                        if ($has && $has->status == 1) {
+                            $has->status     = 3;
+                            $has->updated_at = date('Y-m-d H:i:s');
+                            $has->save();
+
+                        } else {
+                            throw new \Exception('编码为:【' . $v . '】已处理请不要重复提交!');
+                        }
+
+                        Db::commit();
+                    } catch (\Throwable $exception) {
+                        Db::rollBack();
+                        throw new \Exception($exception->getMessage());
+                    }
+                }
+            } catch (\Throwable $exception) {
+                return $this->fail($exception->getMessage());
+            }
+            return $this->success();
+        }
+
+
+    }

+ 68 - 0
plugin/admin/app/controller/PayAisleController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\PayAisle;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 支付通道 
+ */
+class PayAisleController extends Crud
+{
+    
+    /**
+     * @var PayAisle
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new PayAisle;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('pay-aisle/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('pay-aisle/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+    */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('pay-aisle/update');
+    }
+
+}

+ 217 - 0
plugin/admin/app/controller/PayorderController.php

@@ -0,0 +1,217 @@
+<?php
+
+    namespace plugin\admin\app\controller;
+
+    use app\api\repositories\PayRepositories;
+    use app\business\PayorderBusiness;
+    use Illuminate\Support\Arr;
+    use plugin\admin\app\model\ArticleType;
+    use plugin\admin\app\model\Good;
+    use plugin\admin\app\model\PayAisle;
+    use Respect\Validation\Validator;
+    use support\Db;
+    use support\Request;
+    use support\Response;
+    use plugin\admin\app\model\Payorder;
+    use plugin\admin\app\controller\Crud;
+    use support\exception\BusinessException;
+
+    /**
+     * 支付订单
+     */
+    class PayorderController extends Crud
+    {
+
+        /**
+         * @var Payorder
+         */
+        protected $model = null;
+
+        /**
+         * 构造函数
+         * @return void
+         */
+        public function __construct()
+        {
+            $this->model = new Payorder;
+        }
+
+        /**
+         * 浏览
+         * @return Response
+         */
+        public function index(): Response
+        {
+            return view('payorder/index');
+        }
+
+        /**
+         * 插入
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException
+         */
+        public function insert(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+                return parent::insert($request);
+            }
+            return view('payorder/insert');
+        }
+
+        /**
+         * 更新
+         * @param Request $request
+         * @return Response
+         * @throws BusinessException
+         */
+        public function update(Request $request): Response
+        {
+            if ($request->method() === 'POST') {
+                return parent::update($request);
+            }
+            return view('payorder/update');
+        }
+
+        public function select(Request $request): Response
+        {
+            $param = $request->all();
+            $data  = Payorder::query()->where(function ($query) use ($param) {
+                if (Arr::get($param, 'created_at.0') && Arr::get($param, 'created_at.1')) {
+                    $query->whereBetween('created_at', [$param['created_at'][0], $param['created_at'][1]]);
+                } elseif (Arr::get($param, 'created_at.0')) {
+                    $query->where('created_at', '>=', $param['created_at'][0]);
+                } elseif (Arr::get($param, 'created_at.1')) {
+                    $query->where('created_at', '<=', $param['created_at'][1]);
+                }
+
+                if (Arr::get($param, 'order_no')) {
+                    $query->where('order_no', 'like', '%' . $param['order_no'] . '%');
+                }
+
+                if (Arr::get($param, 'pay_type')) {
+                    $query->where('pay_type', $param['pay_type']);
+                }
+                if (Arr::get($param, 'is_pay')) {
+
+                    $query->where('is_pay', $param['is_pay']);
+                }
+//                if (Arr::get($param, 'goods_type')) {
+//
+//                    $query->where('goods_type', $param['goods_type']);
+//                }
+
+            })->whereExists(function ($query) use ($param) {
+                $query->from('wa_users')->whereRaw('wa_users.id=wa_payorder.user_id');
+                if (Arr::get($param, 'user_name')) {
+                    $query->where('name', 'like', '%' . $param['user_name'] . '%');
+                }
+                if (Arr::get($param, 'user_mobile')) {
+                    $query->where('mobile', 'like', '%' . $param['user_mobile'] . '%');
+                }
+            })
+                ->with('userData:id,name,mobile');
+            if (Arr::get($param, 'field')) {
+                $order = 'asc';
+                if (Arr::get($param, 'order')) {
+                    $order = 'desc';
+                }
+                $data = $data->orderBy($param['field'], $order);
+            } else {
+                $data = $data->orderByDesc('id');
+            }
+            $data = $data->paginate(Arr::get($param, 'limit', 10))->toArray();
+            $arr  = [];
+            $Good = Good::query();
+            foreach ($data['data'] as $k => $v) {
+                $pataisle = PayAisle::query()->where('characteristic', $v['pay_characteristic'])->first();
+                if ($pataisle) {
+                    $pay_characteristic_name = $pataisle['name'] . '--' . $pataisle['title'];
+                } else {
+                    $pay_characteristic_name = '';
+                }
+                $goodslist = (clone $Good)->where('id', $v['goods_id'])->first();
+                if(empty($v['sign_record_id'])){
+                    $goods_name = (clone $Good)->where('id', $v['goods_id'])->value('name');
+                }else{
+                    $goods_name = $goodslist->square.'-'.'邮政保价';
+                }
+                if($v['is_prestore']==1){
+                    $goods_name = $goodslist->square.'-'.'预存激活';
+                }
+
+                if($goodslist->type==8){
+                    $goods_name = '缴纳支付 -- '.$goodslist->square;
+                }
+                if($goodslist->type==10){
+                    $goods_name = '跨行联网 -- '.$goodslist->square;
+                }
+
+                $arr[] = [
+                    'bid_name'                => $goods_name,
+                    'user_name'               => $v['user_data']['name'],
+                    'user_mobile'             => $v['user_data']['mobile'],
+                    'pay_no'                  => $v['pay_no'],
+                    'pay_type'                => $v['pay_type'],
+                    'pay_characteristic_name' => $pay_characteristic_name,
+                    'pay_characteristic'      => $v['pay_characteristic'],
+                    'order_no'                => $v['order_no'],
+                    'money'                   => $v['money'],
+                    'is_pay'                  => $v['is_pay'],
+                    'created_at'              => $v['created_at'],
+                    'id'                      => $v['id'],
+                    'img'                     => $v['img'],
+                ];
+
+
+            }
+            return json(['code' => 0, 'data' => $arr, 'msg' => 'ok', 'count' => $data['total']]);
+        }
+
+        /** 审核通过
+         * @param Request $request
+         * @return Response
+         */
+        public function audit(Request $request): Response
+        {
+            $param = $request->all();
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->setName('标识'),
+                ]);
+                $data = Payorder::query()->where('id', $param['id'])->first();
+                if (empty($data)) {
+                    throw new \Exception('非法操作');
+                }
+                if ($data->is_pay != 1) {
+                    throw new \Exception('订单已处理');
+                }
+                PayorderBusiness::payorderSave($data->toArray());
+
+
+                Db::commit();
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return json(['code' => 1, 'msg' => $exception->getMessage()]);
+            }
+            return json(['code' => 0, 'msg' => '成功']);
+        }
+
+        /** 支付渠道
+         * @return void
+         */
+        public function addselect(Request $request): Response
+        {
+            $arr  = [];
+            $data = PayAisle::query()->selectRaw('characteristic,name,title')->get()->toArray();
+            foreach ($data as $k => $v) {
+                $arr[] = [
+                    'value' => $v['characteristic'],
+                    'name'  => $v['name'] . '--' . $v['title'],
+                ];
+            }
+            return json(['code' => 0, 'data' => $arr, 'msg' => 'ok']);
+        }
+
+    }

+ 549 - 0
plugin/admin/app/controller/PluginController.php

@@ -0,0 +1,549 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use GuzzleHttp\Client;
+use GuzzleHttp\Exception\GuzzleException;
+use plugin\admin\app\common\Util;
+use plugin\admin\app\controller\Base;
+use process\Monitor;
+use support\exception\BusinessException;
+use support\Log;
+use support\Request;
+use support\Response;
+use ZIPARCHIVE;
+use function array_diff;
+use function ini_get;
+use function scandir;
+use const DIRECTORY_SEPARATOR;
+use const PATH_SEPARATOR;
+
+class PluginController extends Base
+{
+    /**
+     * 不需要鉴权的方法
+     * @var string[]
+     */
+    protected $noNeedAuth = ['schema', 'captcha'];
+
+    /**
+     * @param Request $request
+     * @return string
+     * @throws GuzzleException
+     */
+    public function index(Request $request)
+    {
+        $client = $this->httpClient();
+        $response = $client->get("/webman-admin/apps");
+        return (string)$response->getBody();
+    }
+
+    /**
+     * 列表
+     * @param Request $request
+     * @return Response
+     * @throws GuzzleException
+     */
+    public function list(Request $request): Response
+    {
+        $installed = $this->getLocalPlugins();
+
+        $client = $this->httpClient();
+        $query = $request->get();
+        $query['version'] = $this->getAdminVersion();
+        $response = $client->get('/api/app/list', ['query' => $query]);
+        $content = $response->getBody()->getContents();
+        $data = json_decode($content, true);
+        if (!$data) {
+            $msg = "/api/app/list return $content";
+            echo "msg\r\n";
+            Log::error($msg);
+            return $this->json(1, '获取数据出错');
+        }
+        $disabled = is_phar();
+        foreach ($data['data']['items'] as $key => $item) {
+            $name = $item['name'];
+            $data['data']['items'][$key]['installed'] = $installed[$name] ?? 0;
+            $data['data']['items'][$key]['disabled'] = $disabled;
+        }
+        $items = $data['data']['items'];
+        $count = $data['data']['total'];
+        return json(['code' => 0, 'msg' => 'ok', 'data' => $items, 'count' => $count]);
+    }
+
+    /**
+     * 安装
+     * @param Request $request
+     * @return Response
+     * @throws GuzzleException|BusinessException
+     */
+    public function install(Request $request): Response
+    {
+        $name = $request->post('name');
+        $version = $request->post('version');
+        $installed_version = $this->getPluginVersion($name);
+        if (!$name || !$version) {
+            return $this->json(1, '缺少参数');
+        }
+
+        $user = session('app-plugin-user');
+        if (!$user) {
+            return $this->json(-1, '请登录');
+        }
+
+        // 获取下载zip文件url
+        $data = $this->getDownloadUrl($name, $version);
+        if ($data['code'] != 0) {
+            return $this->json($data['code'], $data['msg'], $data['data'] ?? []);
+        }
+
+        // 下载zip文件
+        $base_path = base_path() . "/plugin/$name";
+        $zip_file = "$base_path.zip";
+        $extract_to = base_path() . '/plugin/';
+        $this->downloadZipFile($data['data']['url'], $zip_file);
+
+        $has_zip_archive = class_exists(ZipArchive::class, false);
+        if (!$has_zip_archive) {
+            $cmd = $this->getUnzipCmd($zip_file, $extract_to);
+            if (!$cmd) {
+                throw new BusinessException('请给php安装zip模块或者给系统安装unzip命令');
+            }
+            if (!function_exists('proc_open')) {
+                throw new BusinessException('请解除proc_open函数的禁用或者给php安装zip模块');
+            }
+        }
+
+        Util::pauseFileMonitor();
+        try {
+            // 解压zip到plugin目录
+            if ($has_zip_archive) {
+                $zip = new ZipArchive;
+                $zip->open($zip_file, ZIPARCHIVE::CHECKCONS);
+            }
+
+            $context = null;
+            $install_class = "\\plugin\\$name\\api\\Install";
+            if ($installed_version) {
+                // 执行beforeUpdate
+                if (class_exists($install_class) && method_exists($install_class, 'beforeUpdate')) {
+                    $context = call_user_func([$install_class, 'beforeUpdate'], $installed_version, $version);
+                }
+            }
+
+            if (!empty($zip)) {
+                $zip->extractTo(base_path() . '/plugin/');
+                unset($zip);
+            } else {
+                $this->unzipWithCmd($cmd);
+            }
+
+            unlink($zip_file);
+
+            if ($installed_version) {
+                // 执行update更新
+                if (class_exists($install_class) && method_exists($install_class, 'update')) {
+                    call_user_func([$install_class, 'update'], $installed_version, $version, $context);
+                }
+            } else {
+                // 执行install安装
+                if (class_exists($install_class) && method_exists($install_class, 'install')) {
+                    call_user_func([$install_class, 'install'], $version);
+                }
+            }
+        } finally {
+            Util::resumeFileMonitor();
+        }
+
+        Util::reloadWebman();
+
+        return $this->json(0);
+    }
+
+    /**
+     * 卸载
+     * @param Request $request
+     * @return Response
+     */
+    public function uninstall(Request $request): Response
+    {
+        $name = $request->post('name');
+        $version = $request->post('version');
+        if (!$name || !preg_match('/^[a-zA-Z0-9_]+$/', $name)) {
+            return $this->json(1, '参数错误');
+        }
+
+        // 获得插件路径
+        clearstatcache();
+        $path = get_realpath(base_path() . "/plugin/$name");
+        if (!$path || !is_dir($path)) {
+            return $this->json(1, '已经删除');
+        }
+
+        // 执行uninstall卸载
+        $install_class = "\\plugin\\$name\\api\\Install";
+        if (class_exists($install_class) && method_exists($install_class, 'uninstall')) {
+            call_user_func([$install_class, 'uninstall'], $version);
+        }
+
+        // 删除目录
+        clearstatcache();
+        if (is_dir($path)) {
+            $monitor_support_pause = method_exists(Monitor::class, 'pause');
+            if ($monitor_support_pause) {
+                Monitor::pause();
+            }
+            try {
+                $this->rmDir($path);
+            } finally {
+                if ($monitor_support_pause) {
+                    Monitor::resume();
+                }
+            }
+        }
+        clearstatcache();
+
+        Util::reloadWebman();
+
+        return $this->json(0);
+    }
+
+    /**
+     * 支付
+     * @param Request $request
+     * @return string|Response
+     * @throws GuzzleException
+     */
+    public function pay(Request $request)
+    {
+        $app = $request->get('app');
+        if (!$app) {
+            return response('app not found');
+        }
+        $token = session('app-plugin-token');
+        if (!$token) {
+            return 'Please login workerman.net';
+        }
+        $client = $this->httpClient();
+        $response = $client->get("/payment/app/$app/$token");
+        return (string)$response->getBody();
+    }
+
+    /**
+     * 登录验证码
+     * @param Request $request
+     * @return Response
+     * @throws GuzzleException
+     */
+    public function captcha(Request $request): Response
+    {
+        $client = $this->httpClient();
+        $response = $client->get('/user/captcha?type=login');
+        $sid_str = $response->getHeaderLine('Set-Cookie');
+        if (preg_match('/PHPSID=([a-zA-Z_0-9]+?);/', $sid_str, $match)) {
+            $sid = $match[1];
+            session()->set('app-plugin-token', $sid);
+        }
+        return response($response->getBody()->getContents())->withHeader('Content-Type', 'image/jpeg');
+    }
+
+    /**
+     * 登录官网
+     * @param Request $request
+     * @return Response|string
+     * @throws GuzzleException
+     */
+    public function login(Request $request)
+    {
+        $client = $this->httpClient();
+        if ($request->method() === 'GET') {
+            $response = $client->get("/webman-admin/login");
+            return (string)$response->getBody();
+        }
+
+        $response = $client->post('/api/user/login', [
+            'form_params' => [
+                'email' => $request->post('username'),
+                'password' => $request->post('password'),
+                'captcha' => $request->post('captcha')
+            ]
+        ]);
+        $content = $response->getBody()->getContents();
+        $data = json_decode($content, true);
+        if (!$data) {
+            $msg = "/api/user/login return $content";
+            echo "msg\r\n";
+            Log::error($msg);
+            return $this->json(1, '发生错误');
+        }
+        if ($data['code'] != 0) {
+            return $this->json($data['code'], $data['msg']);
+        }
+        session()->set('app-plugin-user', [
+            'uid' => $data['data']['uid']
+        ]);
+        return $this->json(0);
+    }
+
+    /**
+     * 获取zip下载url
+     * @param $name
+     * @param $version
+     * @return mixed
+     * @throws BusinessException
+     * @throws GuzzleException
+     */
+    protected function getDownloadUrl($name, $version)
+    {
+        $client = $this->httpClient();
+        $response = $client->get("/app/download/$name?version=$version");
+
+        $content = $response->getBody()->getContents();
+        $data = json_decode($content, true);
+        if (!$data) {
+            $msg = "/api/app/download return $content";
+            Log::error($msg);
+            throw new BusinessException('访问官方接口失败 ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
+        }
+        if ($data['code'] && $data['code'] != -1 && $data['code'] != -2) {
+            throw new BusinessException($data['msg']);
+        }
+        if ($data['code'] == 0 && !isset($data['data']['url'])) {
+            throw new BusinessException('官方接口返回数据错误');
+        }
+        return $data;
+    }
+
+    /**
+     * 下载zip
+     * @param $url
+     * @param $file
+     * @return void
+     * @throws BusinessException
+     * @throws GuzzleException
+     */
+    protected function downloadZipFile($url, $file)
+    {
+        $client = $this->downloadClient();
+        $response = $client->get($url);
+        $body = $response->getBody();
+        $status = $response->getStatusCode();
+        if ($status == 404) {
+            throw new BusinessException('安装包不存在');
+        }
+        $zip_content = $body->getContents();
+        if (empty($zip_content)) {
+            throw new BusinessException('安装包不存在');
+        }
+        file_put_contents($file, $zip_content);
+    }
+
+    /**
+     * 获取系统支持的解压命令
+     * @param $zip_file
+     * @param $extract_to
+     * @return mixed|string|null
+     */
+    protected function getUnzipCmd($zip_file, $extract_to)
+    {
+        if ($cmd = $this->findCmd('unzip')) {
+            $cmd = "$cmd -o -qq $zip_file -d $extract_to";
+        } else if ($cmd = $this->findCmd('7z')) {
+            $cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
+        } else if ($cmd = $this->findCmd('7zz')) {
+            $cmd = "$cmd x -bb0 -y $zip_file -o$extract_to";
+        }
+        return $cmd;
+    }
+
+    /**
+     * 使用解压命令解压
+     * @param $cmd
+     * @return void
+     * @throws BusinessException
+     */
+    protected function unzipWithCmd($cmd)
+    {
+        $desc = [
+            0 => ["pipe", "r"],
+            1 => ["pipe", "w"],
+            2 => ["pipe", "w"],
+        ];
+        $handler = proc_open($cmd, $desc, $pipes);
+        if (!is_resource($handler)) {
+            throw new BusinessException("解压zip时出错:proc_open调用失败");
+        }
+        $err = fread($pipes[2], 1024);
+        fclose($pipes[2]);
+        proc_close($handler);
+        if ($err) {
+            throw new BusinessException("解压zip时出错:$err");
+        }
+    }
+
+    /**
+     * 获取已安装的插件列表
+     * @return array
+     */
+    protected function getLocalPlugins(): array
+    {
+        clearstatcache();
+        $installed = [];
+        $plugin_names = array_diff(scandir(base_path() . '/plugin/'), array('.', '..')) ?: [];
+        foreach ($plugin_names as $plugin_name) {
+            if (is_dir(base_path() . "/plugin/$plugin_name") && $version = $this->getPluginVersion($plugin_name)) {
+                $installed[$plugin_name] = $version;
+            }
+        }
+        return $installed;
+    }
+
+    /**
+     * 获取已安装的插件列表
+     * @param Request $request
+     * @return Response
+     */
+    public function getInstalledPlugins(Request $request): Response
+    {
+        return $this->json(0, 'ok', $this->getLocalPlugins());
+    }
+    
+
+    /**
+     * 获取本地插件版本
+     * @param $name
+     * @return array|mixed|null
+     */
+    protected function getPluginVersion($name)
+    {
+        if (!is_file($file = base_path() . "/plugin/$name/config/app.php")) {
+            return null;
+        }
+        $config = include $file;
+        return $config['version'] ?? null;
+    }
+
+    /**
+     * 获取webman/admin版本
+     * @return string
+     */
+    protected function getAdminVersion(): string
+    {
+        return config('plugin.admin.app.version', '');
+    }
+
+    /**
+     * 删除目录
+     * @param $src
+     * @return void
+     */
+    protected function rmDir($src)
+    {
+        $dir = opendir($src);
+        while (false !== ($file = readdir($dir))) {
+            if (($file != '.') && ($file != '..')) {
+                $full = $src . '/' . $file;
+                if (is_dir($full)) {
+                    $this->rmDir($full);
+                } else {
+                    unlink($full);
+                }
+            }
+        }
+        closedir($dir);
+        rmdir($src);
+    }
+
+    /**
+     * 获取httpclient
+     * @return Client
+     */
+    protected function httpClient(): Client
+    {
+        // 下载zip
+        $options = [
+            'base_uri' => config('plugin.admin.app.plugin_market_host'),
+            'timeout' => 60,
+            'connect_timeout' => 5,
+            'verify' => false,
+            'http_errors' => false,
+            'headers' => [
+                'Referer' => \request()->fullUrl(),
+                'User-Agent' => 'webman-app-plugin',
+                'Accept' => 'application/json;charset=UTF-8',
+            ]
+        ];
+        if ($token = session('app-plugin-token')) {
+            $options['headers']['Cookie'] = "PHPSID=$token;";
+        }
+        return new Client($options);
+    }
+
+    /**
+     * 获取下载httpclient
+     * @return Client
+     */
+    protected function downloadClient(): Client
+    {
+        // 下载zip
+        $options = [
+            'timeout' => 59,
+            'connect_timeout' => 5,
+            'verify' => false,
+            'http_errors' => false,
+            'headers' => [
+                'Referer' => \request()->fullUrl(),
+                'User-Agent' => 'webman-app-plugin',
+            ]
+        ];
+        if ($token = session('app-plugin-token')) {
+            $options['headers']['Cookie'] = "PHPSID=$token;";
+        }
+        return new Client($options);
+    }
+
+    /**
+     * 查找系统命令
+     * @param string $name
+     * @param string|null $default
+     * @param array $extraDirs
+     * @return mixed|string|null
+     */
+    protected function findCmd(string $name, string $default = null, array $extraDirs = [])
+    {
+        if (ini_get('open_basedir')) {
+            $searchPath = array_merge(explode(PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
+            $dirs = [];
+            foreach ($searchPath as $path) {
+                if (@is_dir($path)) {
+                    $dirs[] = $path;
+                } else {
+                    if (basename($path) == $name && @is_executable($path)) {
+                        return $path;
+                    }
+                }
+            }
+        } else {
+            $dirs = array_merge(
+                explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
+                $extraDirs
+            );
+        }
+
+        $suffixes = [''];
+        if ('\\' === DIRECTORY_SEPARATOR) {
+            $pathExt = getenv('PATHEXT');
+            $suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com'], $suffixes);
+        }
+        foreach ($suffixes as $suffix) {
+            foreach ($dirs as $dir) {
+                if (@is_file($file = $dir . DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === DIRECTORY_SEPARATOR || @is_executable($file))) {
+                    return $file;
+                }
+            }
+        }
+
+        return $default;
+    }
+
+}

+ 68 - 0
plugin/admin/app/controller/RaffleController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace plugin\admin\app\controller;
+
+use support\Request;
+use support\Response;
+use plugin\admin\app\model\Raffle;
+use plugin\admin\app\controller\Crud;
+use support\exception\BusinessException;
+
+/**
+ * 抽奖规则 
+ */
+class RaffleController extends Crud
+{
+    
+    /**
+     * @var Raffle
+     */
+    protected $model = null;
+
+    /**
+     * 构造函数
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->model = new Raffle;
+    }
+    
+    /**
+     * 浏览
+     * @return Response
+     */
+    public function index(): Response
+    {
+        return view('raffle/index');
+    }
+
+    /**
+     * 插入
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+     */
+    public function insert(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::insert($request);
+        }
+        return view('raffle/insert');
+    }
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     * @throws BusinessException
+    */
+    public function update(Request $request): Response
+    {
+        if ($request->method() === 'POST') {
+            return parent::update($request);
+        }
+        return view('raffle/update');
+    }
+
+}

+ 0 - 0
plugin/admin/app/controller/RaffleLogController.php


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä