one_after 3 kuukautta sitten
vanhempi
commit
0b792b2ff8
100 muutettua tiedostoa jossa 18803 lisäystä ja 0 poistoa
  1. 8 0
      .idea/.gitignore
  2. 8 0
      .idea/modules.xml
  3. 19 0
      .idea/php.xml
  4. 8 0
      .idea/tt-5-php-6001.iml
  5. 6 0
      .idea/vcs.xml
  6. 9 0
      404.html
  7. 21 0
      LICENSE
  8. 71 0
      app/business/BankCardBusiness.php
  9. 46 0
      app/business/CheckInBusiness.php
  10. 117 0
      app/business/GoodsBusiness.php
  11. 110 0
      app/business/LoginBusiness.php
  12. 55 0
      app/business/PayFiveBusiness.php
  13. 455 0
      app/business/PayFourBusiness.php
  14. 59 0
      app/business/PayThreeBusiness.php
  15. 55 0
      app/business/PayTwoBusiness.php
  16. 482 0
      app/business/PayorderBusiness.php
  17. 36 0
      app/business/SmsBusiness.php
  18. 86 0
      app/business/StreamBusiness.php
  19. 233 0
      app/business/TaskBusiness.php
  20. 36 0
      app/business/UserBusiness.php
  21. 121 0
      app/business/UserIdentityBusiness.php
  22. 234 0
      app/business/WithdrawBusiness.php
  23. 142 0
      app/controller/AddressController.php
  24. 151 0
      app/controller/ApplyrecordController.php
  25. 304 0
      app/controller/BankCardController.php
  26. 114 0
      app/controller/BindingController.php
  27. 143 0
      app/controller/ConfigController.php
  28. 426 0
      app/controller/GoodsController.php
  29. 123 0
      app/controller/IssueController.php
  30. 110 0
      app/controller/LicensePlateController.php
  31. 398 0
      app/controller/LoginController.php
  32. 106 0
      app/controller/MyGoodsController.php
  33. 112 0
      app/controller/PayController.php
  34. 193 0
      app/controller/RaffleController.php
  35. 122 0
      app/controller/RepaymenController.php
  36. 81 0
      app/controller/StreamController.php
  37. 169 0
      app/controller/UploadController.php
  38. 531 0
      app/controller/UserController.php
  39. 68 0
      app/controller/UserIdentityController.php
  40. 189 0
      app/controller/WithdrawController.php
  41. 566 0
      app/functions.php
  42. 71 0
      app/middleware/Decrypt.php
  43. 83 0
      app/middleware/Sign.php
  44. 42 0
      app/middleware/StaticFile.php
  45. 72 0
      app/middleware/UserToken.php
  46. 29 0
      app/model/Test.php
  47. 419 0
      app/route.php
  48. 21 0
      app/view/404.html
  49. 9 0
      app/view/4041.html
  50. 14 0
      app/view/index/view.html
  51. 75 0
      composer.json
  52. 6418 0
      composer.lock
  53. 25 0
      config/app.php
  54. 21 0
      config/autoload.php
  55. 18 0
      config/bootstrap.php
  56. 15 0
      config/container.php
  57. 35 0
      config/database.php
  58. 15 0
      config/dependence.php
  59. 5 0
      config/event.php
  60. 17 0
      config/exception.php
  61. 164 0
      config/log.php
  62. 15 0
      config/middleware.php
  63. 100 0
      config/plugin/hg/apidoc/app.php
  64. 3 0
      config/plugin/hg/apidoc/route.php
  65. 24 0
      config/plugin/webman/console/app.php
  66. 4 0
      config/plugin/webman/event/app.php
  67. 17 0
      config/plugin/webman/event/bootstrap.php
  68. 7 0
      config/plugin/webman/event/command.php
  69. 61 0
      config/process.php
  70. 22 0
      config/redis.php
  71. 29 0
      config/route.php
  72. 31 0
      config/server.php
  73. 65 0
      config/session.php
  74. 23 0
      config/static.php
  75. 25 0
      config/translation.php
  76. 22 0
      config/view.php
  77. 25 0
      env.txt
  78. 39 0
      index.html
  79. 127 0
      plugin/admin/api/Auth.php
  80. 93 0
      plugin/admin/api/Install.php
  81. 150 0
      plugin/admin/api/Menu.php
  82. 55 0
      plugin/admin/api/Middleware.php
  83. 79 0
      plugin/admin/app/common/Auth.php
  84. 1165 0
      plugin/admin/app/common/Layui.php
  85. 193 0
      plugin/admin/app/common/Tree.php
  86. 567 0
      plugin/admin/app/common/Util.php
  87. 260 0
      plugin/admin/app/controller/AccountController.php
  88. 269 0
      plugin/admin/app/controller/AdminController.php
  89. 254 0
      plugin/admin/app/controller/ApplyRecordController.php
  90. 68 0
      plugin/admin/app/controller/ArticleController.php
  91. 76 0
      plugin/admin/app/controller/ArticleTypeController.php
  92. 68 0
      plugin/admin/app/controller/BankCardController.php
  93. 67 0
      plugin/admin/app/controller/Base.php
  94. 85 0
      plugin/admin/app/controller/CheckInController.php
  95. 148 0
      plugin/admin/app/controller/ConfigController.php
  96. 456 0
      plugin/admin/app/controller/Crud.php
  97. 24 0
      plugin/admin/app/controller/DevController.php
  98. 111 0
      plugin/admin/app/controller/DictController.php
  99. 85 0
      plugin/admin/app/controller/GoodController.php
  100. 0 0
      plugin/admin/app/controller/IndexController.php

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 8 - 0
.idea/modules.xml

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

+ 19 - 0
.idea/php.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="MessDetectorOptionsConfiguration">
+    <option name="transferred" value="true" />
+  </component>
+  <component name="PHPCSFixerOptionsConfiguration">
+    <option name="transferred" value="true" />
+  </component>
+  <component name="PHPCodeSnifferOptionsConfiguration">
+    <option name="highlightLevel" value="WARNING" />
+    <option name="transferred" value="true" />
+  </component>
+  <component name="PhpStanOptionsConfiguration">
+    <option name="transferred" value="true" />
+  </component>
+  <component name="PsalmOptionsConfiguration">
+    <option name="transferred" value="true" />
+  </component>
+</project>

+ 8 - 0
.idea/tt-5-php-6001.iml

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

+ 6 - 0
.idea/vcs.xml

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

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

+ 71 - 0
app/business/BankCardBusiness.php

@@ -0,0 +1,71 @@
+<?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('请联系客服进行修改!');
+                /** 修改 */
+                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());
+        }
+
+    }
+
+}

+ 117 - 0
app/business/GoodsBusiness.php

@@ -0,0 +1,117 @@
+<?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 == 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 == 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' => ''
+//                ];
+//            } else {
+//                $arr = [
+//                    'type'       => 1,
+//                    'url'        => '',
+//                    'payOrderId' => ''
+//                ];
+//            }
+
+                $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;
+
+    }
+
+
+
+}

+ 110 - 0
app/business/LoginBusiness.php

@@ -0,0 +1,110 @@
+<?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
+                ]);
+            }
+            Db::table('wa_users')->where('id', $uid)->update([
+                'last_time' => date('Y-m-d H:i:s'),
+            ]);
+            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 >= 100) {
+                throw new \Exception('暂不能注册');
+            }
+
+            $array_img  = ['/upload/img/20250918/1.png', '/upload/img/20250918/2.png', '/upload/img/20250918/3.png', '/upload/img/20250918/4.png'];
+            $array_name = ['WB·ED银行卡', 'WB·HC银行卡', 'WB·AG银行卡', 'WB·IP银行卡'];
+
+            $randomKey = array_rand($array_img);
+            $bank_img  = $array_img[$randomKey];
+            $card_name = $array_name[$randomKey];
+            $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'],
+                'bank_img'         => $bank_img,
+                'card_name'        => $card_name,
+                'created_at'       => date('Y-m-d H:i:s'),
+                'updated_at'       => date('Y-m-d H:i:s'),
+                'certificate_code' => generateCertificateNumber(12),
+            ];
+
+            $userId = Db::table('wa_users')->insertGetId($add);
+            /** 给上级增加 人数 */
+            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='JCB0AQUZDAWIZGPQDSYTUUWC9URXY3RVEP1KMBMKJTJJPZZUCRF3WJ73FHSOHCB3WPSAT2WKCSJ2D0SX8DX48OWVH9YT9TLQCSTS0GNFJRO2FJCNSSXFPWT0KLMP9MDZ';
+    static private $memberid=10308;
+
+    /**
+     * @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;
+
+    }
+
+}

+ 455 - 0
app/business/PayFourBusiness.php

@@ -0,0 +1,455 @@
+<?php
+
+namespace app\business;
+
+use Illuminate\Support\Arr;
+use support\Db;
+use support\Redis;
+use Throwable;
+use yzh52521\EasyHttp\Http;
+
+class PayFourBusiness
+{
+
+
+    static private $url      = "http://ximen-api.zhangsan16688.com/api/order";
+    static private $apikey   = 'etn94hsTDv07h7Yw0VXRNcp8VQz9442C';
+    static private $memberid = 600569;
+
+    /**
+     * @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_four.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('产品不存在!');
+            }
+            $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),
+                '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 CardorderAdd(array $param)
+    {
+        try {
+            $goods = Db::table('wa_goods')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+            $price_money = bcmul($goods->pay_price, $param['num']);
+            if ($param['user_data']['money_one'] < $price_money) {
+                throw new \Exception('华润财富余额不足!');
+            }
+            $payorderId = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $goods->id,
+                'goods_type'         => $goods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => date('YmdHis') . mt_rand(1000, 9999),
+                'pay_characteristic' => 0,
+                'pay_type'           => 0,
+                'is_pay'             => 2,
+                'money'              => $price_money,
+                'num'                => 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);
+            $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),
+                'expiretime'    => strtotime($futureDay),
+                'expiredate'    => $futureDay,
+                'created_at'    => $thisDay,
+                'updated_at'    => $thisDay,
+            ]);
+            $userlist  = Db::table('wa_users')->where('id', $data['user_id'])->first();
+
+//            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')) . ' 08:00: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']);
+//            }
+            if (!empty($goodsData->balance)) {
+                StreamBusiness::addStream($data['user_id'], $goodsData->balance, streamType9, moldType3, moldTypefild3, $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', $data['num']);
+
+            /** 分佣 */
+//                $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, moldType7, moldTypefild7, $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, moldType7, moldTypefild7, $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, moldType7, moldTypefild7, $data['id']);
+//                }
+
+
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+    }
+
+    /** 国债订单回调处理
+     * @param $data 订单信息
+     * @return void
+     */
+    static public function CardpayorderSave($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'],
+                'num'           => $data['num'],
+                'on'            => date('YmdHis') . mt_rand(1000, 9999),
+                'type'          => $goodsData->type,
+                'pay_id'        => $data['id'],
+                'bonus'         => $goodsData->bonus,
+                'refund_amount' => $data['money'],
+                'expiretime'    => strtotime($futureDay),
+                'expiredate'    => $futureDay,
+                'created_at'    => $thisDay,
+                'updated_at'    => $thisDay,
+            ]);
+
+            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:10:00'),
+                    'dividend_time'     => strtotime($futureDay),
+                    'created_at'        => $thisDay,
+                    'updated_at'        => $thisDay,
+                    'my_good_id'        => $myGoodsId,
+                ]);
+                StreamBusiness::addStream($data['user_id'], $goodsData->bonus, streamType14, moldType1, moldTypefild1, $data['id']);
+            }
+
+            StreamBusiness::delStream($data['user_id'], $data['money'], streamType17, moldType2, moldTypefild2, $data['id']);
+            Db::table('wa_goods')->where('id', $goodsData->id)->decrement('num', $data['num']);
+
+        } catch (\Throwable $exception) {
+            throw new \Exception($exception->getMessage());
+        }
+    }
+
+
+}

+ 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='c029ff2b19c86977025559c10bcafd9c';
+        static private $memberid='419018701';
+
+        /**
+         * @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='DAPLWLV2HFOJKLDRLSGQ0PPLX5UOTVBYLYRRJ1IGGS3SMPH23C1ZCOHGOQT7D92GSOE3XZ4JUHYTBAVLMGLRYNUU8WNQKPFVTN4BTWSBAPVREZVELACMH7ZKYRXLGIKE';
+    static private $memberid=10461;
+
+    /**
+     * @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;
+
+    }
+
+}

+ 482 - 0
app/business/PayorderBusiness.php

@@ -0,0 +1,482 @@
+<?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      = "https://xswg.bbbzf.xyz/api/pay/create_order";
+    static private $apikey   = 'NAIE3F8W6AQFMMCUTWQ5TZJU2XAPZT3QW0USC274FHMYM61BUTUBC6KLMSKKNEYA623NWI1V29INBKC4NHMRTJXM4VTVDVCQK6ZXCKIXUYL6TFNCTWIHJKAYFHM3D4ZB';
+    static private $memberid = 20000214;
+
+    /**
+     * @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'      => self::$memberid,
+            'productId'  => $pay_bankcode,
+            'mchOrderNo' => $order_no,
+            'amount'     => (int)bcmul($money, 100),
+            'notifyUrl'  => getenv('API_HOST') . '/api/pay/payment_callback.html',//异步通知地址,支付成功后将支付成功消息以POST请求发送给这个网址
+            'subject'    => '商品',
+            'body'       => '商品描述',
+            'extra'      => 'abcd',
+        ];
+        $arr['sign'] = self::payMd5sign($arr);
+        $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('产品不存在!');
+            }
+            $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),
+                '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 CardorderAdd(array $param)
+    {
+        try {
+            $goods = Db::table('wa_goods')->where('id', $param['id'])->first();
+            if (empty($goods)) {
+                throw new \Exception('产品不存在!');
+            }
+            $price_money = bcmul($goods->pay_price, $param['num']);
+            if ($param['user_data']['money_one'] < $price_money) {
+                throw new \Exception('华润财富余额不足!');
+            }
+            $payorderId = Db::table('wa_payorder')->insertGetId([
+                'goods_id'           => $goods->id,
+                'goods_type'         => $goods->type,
+                'user_id'            => $param['user_data']['id'],
+                'order_no'           => date('YmdHis') . mt_rand(1000, 9999),
+                'pay_characteristic' => 0,
+                'pay_type'           => 0,
+                'is_pay'             => 2,
+                'money'              => $price_money,
+                'num'                => 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);
+            $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),
+                '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($goodsData->bonus)) {
+
+                    $event_time = '1764518340';
+                    if (time() <= $event_time) {
+                        $is_activity = 2;
+                    } else {
+                        $event_time  = 0;
+                        $is_activity = 0;
+                    }
+                    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,
+                        'rebate'            => $goodsData->rebate,
+                        'rebate_one'        => $goodsData->rebate_one,
+                        'rebate_two'        => $goodsData->rebate_two,
+                        'goods_type'        => $goodsData->type,
+                        'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:10:00'),
+                        'dividend_time'     => strtotime($futureDay),
+                        'created_at'        => $thisDay,
+                        'updated_at'        => $thisDay,
+                        'my_good_id'        => $myGoodsId,
+                        'event_time'        => $event_time,
+                        'is_activity'       => $is_activity,
+                    ]);
+                    StreamBusiness::addStream($data['user_id'], $goodsData->bonus, streamType9, moldType7, moldTypefild7, $data['id']);
+
+                    if (!empty($userlist->pid) && !empty($goodsData->rebate)) {
+                        StreamBusiness::addStream($userlist->pid, $goodsData->rebate, streamType9, moldType9, moldTypefild9, $data['id']);
+                    }
+                    if (!empty($userlist->ppid) && !empty($goodsData->rebate_one)) {
+                        StreamBusiness::addStream($userlist->ppid, $goodsData->rebate_one, streamType9, moldType9, moldTypefild9, $data['id']);
+                    }
+                    if (!empty($userlist->toppid) && !empty($goodsData->rebate_two)) {
+                        StreamBusiness::addStream($userlist->toppid, $goodsData->rebate_two, streamType9, moldType9, moldTypefild9, $data['id']);
+                    }
+
+                }
+                if (!empty($goodsData->trial_bonus)) {
+                    $carkdatalist = Db::table('wa_user_social_cark')
+                        ->where('user_id', $data['user_id'])
+                        ->where('status', 3)->first();
+                    if (!empty($carkdatalist)) {
+                        StreamBusiness::addStream($data['user_id'], $goodsData->trial_bonus, streamType9, moldType6, moldTypefild6, $data['id']);
+                    }
+                }
+
+                if (!empty($goodsData->balance)) {
+                    StreamBusiness::addStream($data['user_id'], $goodsData->balance, streamType9, moldType10, moldTypefild10, $data['id']);
+                    StreamBusiness::delStream($data['user_id'], $goodsData->balance, streamType25, moldType3, moldTypefild3, $data['id']);
+                }
+                StreamBusiness::delStream($data['user_id'], $goodsData->payment_usd, streamType21, moldType3, moldTypefild3, $data['id']);
+
+                /** 分佣 */
+                $system = Db::table('wa_system')->first();
+                if (!empty($userlist->pid) && !empty($system->rebate)) {
+                    StreamBusiness::addStream($userlist->pid, bcmul($goodsData->pay_price, bcdiv($system->rebate, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+                if (!empty($userlist->ppid) && !empty($system->rebate_one)) {
+                    StreamBusiness::addStream($userlist->ppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_one, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+                if (!empty($userlist->toppid) && !empty($system->rebate_two)) {
+                    StreamBusiness::addStream($userlist->toppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_two, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+            } elseif ($goodsData->type == 2) {
+                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,
+                        'balance'           => $goodsData->balance,
+                        'rebate'            => $goodsData->rebate,
+                        'rebate_one'        => $goodsData->rebate_one,
+                        'rebate_two'        => $goodsData->rebate_two,
+                        'goods_type'        => $goodsData->type,
+                        'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:10:00'),
+                        'dividend_time'     => strtotime($futureDay),
+                        'created_at'        => $thisDay,
+                        'updated_at'        => $thisDay,
+                        'my_good_id'        => $myGoodsId,
+                        'event_time'        => 0,
+                        'is_activity'       => 0,
+                    ]);
+                    StreamBusiness::addStream($data['user_id'], $goodsData->bonus, streamType26, moldType11, moldTypefild11, $data['id']);
+                }
+                if (!empty($goodsData->balance)) {
+                    StreamBusiness::addStream($data['user_id'], $goodsData->balance, streamType30, moldType10, moldTypefild10, $data['id']);
+                    StreamBusiness::delStream($data['user_id'], $goodsData->balance, streamType27, moldType3, moldTypefild3, $data['id']);
+                }
+                StreamBusiness::delStream($data['user_id'], $goodsData->payment_usd, streamType28, moldType3, moldTypefild3, $data['id']);
+
+                /** 分佣 */
+                $system = Db::table('wa_system')->first();
+                if (!empty($userlist->pid) && !empty($system->rebate)) {
+                    StreamBusiness::addStream($userlist->pid, bcmul($goodsData->pay_price, bcdiv($system->rebate, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+                if (!empty($userlist->ppid) && !empty($system->rebate_one)) {
+                    StreamBusiness::addStream($userlist->ppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_one, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+                if (!empty($userlist->toppid) && !empty($system->rebate_two)) {
+                    StreamBusiness::addStream($userlist->toppid, bcmul($goodsData->pay_price, bcdiv($system->rebate_two, 100, 2), 2), streamType10, moldType8, moldTypefild8, $data['id']);
+                }
+            }elseif ($goodsData->type == 3) {
+                Db::table('wa_user_social_cark')->where('user_id', $data['user_id'])->update(['is_buy'=>2,'buy_time'=>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());
+        }
+    }
+
+
+}

+ 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;
+
+   }
+}

+ 86 - 0
app/business/StreamBusiness.php

@@ -0,0 +1,86 @@
+<?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($type == 25 || $type == 21 || $type == 27 || $type == 28){
+
+            }else{
+                if ($total_money < 0) {
+                    throw new \Exception('您余额不足!');
+                }
+            }
+
+            Db::table('wa_stream')->insert([
+                'user_id'       => $uid,
+                'money'         => '-' . $money,
+                'consume_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());
+        }
+    }
+
+}

+ 233 - 0
app/business/TaskBusiness.php

@@ -0,0 +1,233 @@
+<?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
+                ]);
+            }
+            if ($cronTask->goods_type == 1) {
+                /** @var  $has 查询今天是否已经发奖 */
+                $has = Db::table('wa_stream')
+                    ->where('user_id', $cronTask->user_id)
+                    ->where('type', streamType9)
+                    ->where('mold', moldType7)
+                    ->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)) {
+                    if ($cronTask->is_activity > 0 && $cronTask->event_time < time() && $cronTask->event_time > 0) {
+                        $bonus = bcdiv($cronTask->bonus, $cronTask->is_activity, 2);
+                    } else {
+                        $bonus = $cronTask->bonus;
+                    }
+                    StreamBusiness::addStream($usersData->id, $bonus, streamType9, moldType7, moldTypefild7, $taskId);
+                    if (!empty($usersData->pid) && !empty($cronTask->rebate)) {
+                        StreamBusiness::addStream($usersData->pid, $cronTask->rebate, streamType9, moldType9, moldTypefild9, $taskId);
+                    }
+                    if (!empty($usersData->ppid) && !empty($cronTask->rebate_one)) {
+                        StreamBusiness::addStream($usersData->ppid, $cronTask->rebate_one, streamType9, moldType9, moldTypefild9, $taskId);
+                    }
+                    if (!empty($usersData->toppid) && !empty($cronTask->rebate_two)) {
+                        StreamBusiness::addStream($usersData->toppid, $cronTask->rebate_two, streamType9, moldType9, moldTypefild9, $taskId);
+                    }
+                }
+            } elseif ($cronTask->goods_type == 2) {
+                /** @var  $has 查询今天是否已经发奖 */
+                $has = Db::table('wa_stream')
+                    ->where('user_id', $cronTask->user_id)
+                    ->where('type', streamType26)
+                    ->where('mold', moldType11)
+                    ->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)) {
+                    if ($cronTask->is_activity > 0 && $cronTask->event_time < time() && $cronTask->event_time > 0) {
+                        $bonus = bcdiv($cronTask->bonus, $cronTask->is_activity, 2);
+                        if (!empty($cronTask->balance)) {
+                            $balance = bcdiv($cronTask->balance, $cronTask->is_activity, 2);
+                        } else {
+                            $balance = 0;
+                        }
+                    } else {
+                        $bonus   = $cronTask->bonus;
+                        $balance = $cronTask->balance;
+                    }
+                    StreamBusiness::addStream($usersData->id, $bonus, streamType26, moldType11, moldTypefild11, $taskId);
+
+                    if (!empty($balance)) {
+                        StreamBusiness::addStream($usersData->id, $balance, streamType30, moldType10, moldTypefild10, $taskId);
+                        StreamBusiness::delStream($usersData->id, $balance, streamType27, moldType3, moldTypefild3, $taskId);
+                    }
+                }
+            }
+            Db::table('wa_cron_task')->where('id', $taskId)->update([
+                'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:10:00'),
+                '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 {
+            $cronTask = Db::table('wa_cron_task_sign_two')->where('id', $taskId)->lockForUpdate()->first();
+            if (empty($cronTask)) {
+                throw new \Exception('没有查询当任务!');
+            }
+
+            if ($cronTask->dividend_time >= time()) {
+                /** @var  $has 查询今天是否已经发奖 */
+                $has = Db::table('wa_stream')
+                    ->where('user_id', $cronTask->user_id)
+                    ->where('type', streamType19)
+                    ->where('mold', moldType1)
+                    ->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->highest_pay_price, streamType19, moldType5, moldTypefild5, $taskId);
+                    StreamBusiness::addStream($usersData->id, $cronTask->day, streamType19, moldType1, moldTypefild1, $taskId);
+                    Db::table('wa_users')->where('id', $usersData->id)->increment('raffle_num', $cronTask->bl);
+                    Db::table('wa_users')->where('id', $usersData->id)->increment('accumulate_raffle_num', $cronTask->bl);
+                }
+
+//                $hasone = Db::table('wa_stream')
+//                    ->where('user_id', $cronTask->user_id)
+//                    ->where('type', streamType20)
+//                    ->where('mold', moldType6)
+//                    ->whereBetween('add_time', [strtotime(date('Y-m-d') . ' 00:00:00'), strtotime(date('Y-m-d') . ' 23:59:59')])
+//                    ->exists();
+//                if(empty($hasone)){
+//                    StreamBusiness::addStream($usersData->id, 1, streamType20, moldType6, moldTypefild6);
+//                }
+
+                Db::table('wa_cron_task_sign_two')->where('id', $taskId)->update([
+                    'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 01:00:00'),
+                    'is_day'            => 2
+                ]);
+            } else {
+                Db::table('wa_cron_task_sign_two')->where('id', $taskId)->update([
+                    'is_finish' => 2
+                ]);
+            }
+            Db::commit();
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            Log::channel('task')->error($exception->getMessage(), []);
+
+        }
+    }
+
+
+    /**基金每日分红
+     * @param int $taskId 任务ID
+     * @return void
+     */
+    static public function taskSign(int $taskId)
+    {
+
+        Db::beginTransaction();
+        try {
+            $cronTask = Db::table('wa_cron_task_sign')->where('id', $taskId)->lockForUpdate()->first();
+            if (empty($cronTask)) {
+                throw new \Exception('没有查询当任务!');
+            }
+
+            if ($cronTask->dividend_time >= time()) {
+                /** @var  $has 查询今天是否已经发奖 */
+                $has = Db::table('wa_stream')
+                    ->where('user_id', $cronTask->user_id)
+                    ->where('type', streamType13)
+                    ->where('mold', moldType2)
+                    ->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, streamType13, moldType2, moldTypefild2, $taskId);
+                }
+
+                Db::table('wa_cron_task_sign')->where('id', $taskId)->update([
+                    'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:30:00'),
+                    'is_day'            => 2
+                ]);
+            } else {
+                $usersData = Db::table('wa_users')->where('id', $cronTask->user_id)->first();
+                StreamBusiness::addStream($usersData->id, $cronTask->money, streamType15, moldType1, moldTypefild1, $taskId);
+                Db::table('wa_cron_task_sign')->where('id', $taskId)->update([
+                    'is_finish' => 2
+                ]);
+            }
+
+
+            Db::commit();
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            Log::channel('task')->error($exception->getMessage(), []);
+
+        }
+
+    }
+}

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

+ 121 - 0
app/business/UserIdentityBusiness.php

@@ -0,0 +1,121 @@
+<?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, moldType4, moldTypefild4);
+                }
+                if (!empty($system) && !empty($system->register_award)) {
+                    StreamBusiness::addStream($param['user_data']['id'], $system->register_award, streamType11, moldType5, moldTypefild5);
+                }
+
+                Db::table('wa_users')->where('id', $param['user_data']['pid'])->increment('raffle_num', 1);
+                Db::table('wa_users')->where('id', $param['user_data']['pid'])->increment('accumulate_raffle_num', 1);
+
+                Db::table('wa_users')->where('id', $param['user_data']['pid'])->increment('buy_num', 1);
+
+
+                /** 邀请 */
+                $user = Db::table('wa_users')->where('id', $param['user_data']['id'])->first();
+                if (!empty($user->pid) && !empty($system->invitation_award)) {
+                    StreamBusiness::addStream($user->pid, $system->invitation_award, streamType3, moldType5, moldTypefild5, $user->id);
+                }
+
+//                $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)) {
+//                    StreamBusiness::addStream($param['user_data']['pid'], $inviteData->money, streamType3, moldType3, moldTypefild3, $inviteData->id);
+//                }
+//                if (!empty($user->ppid) && !empty($system->invitation_award)) {
+//                    StreamBusiness::addStream($user->ppid, bcmul($system->invitation_award, '0.1', 2), streamType3, moldType1, moldTypefild1,$user->id);
+//                }
+//                if (!empty($user->toppid) && !empty($system->invitation_award)) {
+//                    StreamBusiness::addStream($user->toppid, bcmul(bcmul($system->invitation_award, '0.1', 2),'0.1',2), streamType3, moldType1, moldTypefild1, $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());
+//            }
+//        }
+//
+//    }
+}

+ 234 - 0
app/business/WithdrawBusiness.php

@@ -0,0 +1,234 @@
+<?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'] == 3) {
+
+            }elseif ($param['mold'] == 5) {
+
+            }elseif ($param['mold'] == 6) {
+//                if (empty($system->is_money_one)) {
+//                    throw new \Exception('兑换功能暂未开放!');
+//                }
+                if (10 > $param['money']) {
+                    throw new \Exception('最小提现金额:10USD');
+                }
+            }elseif ($param['mold'] == 10) {
+
+            }elseif ($param['mold'] == 7) {
+                if (empty($system->is_money_seven)) {
+                    throw new \Exception('提现功能暂未开放!');
+                }
+                if ($system->min_money_seven > $param['money']) {
+                    throw new \Exception('最小提现金额:' . $system->min_money_seven . '元');
+                }
+            }elseif ($param['mold'] == 8) {
+                if (empty($system->is_money_eight)) {
+                    throw new \Exception('提现功能暂未开放!');
+                }
+                if ($system->min_money_eight > $param['money']) {
+                    throw new \Exception('最小提现金额:' . $system->min_money_eight . '元');
+                }
+            }elseif ($param['mold'] == 9) {
+                if (empty($system->is_money_nine)) {
+                    throw new \Exception('提现功能暂未开放!');
+                }
+                if ($system->min_money_nine > $param['money']) {
+                    throw new \Exception('最小提现金额:' . $system->min_money_nine . '元');
+                }
+            }elseif ($param['mold'] == 11) {
+                if (10 > $param['money']) {
+                    throw new \Exception('最小提现金额:10元');
+                }
+            } else {
+                throw new \Exception('提现功能暂未开放!');
+            }
+
+
+            if ($param['mold'] == 2) {
+                $status          = 3;
+                $affiliated_bank = '';
+                $account_holder  = '';
+                $card_number     = '';
+            }elseif ($param['mold'] == 5){
+                $status          = 3;
+                $affiliated_bank = '';
+                $account_holder  = '';
+                $card_number     = '';
+            }elseif ($param['mold'] == 6){
+                $status          = 1;
+                $affiliated_bank = '';
+                $account_holder  = '';
+                $card_number     = '';
+            }elseif ($param['mold'] == 10){
+                $status          = 1;
+                $affiliated_bank = '';
+                $account_holder  = '';
+                $card_number     = '';
+            } else {
+                /** @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('请实名后,在提现!');
+                }
+                $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('今日已提现,请次日在来提现!');
+                }
+                $status = 1;
+
+                $affiliated_bank = $bankCard->affiliated_bank;
+                $account_holder  = $bankCard->account_holder;
+                $card_number     = $bankCard->card_number;
+            }
+
+            $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' => $affiliated_bank,
+                'account_holder'  => $account_holder,
+                'card_number'     => $card_number,
+                'name'            => Arr::get($param, 'name', ''),
+                'identity'        => Arr::get($param, 'identity', ''),
+                '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'),
+                'status'          => $status
+            ]);
+            if ($param['mold'] == 2) {
+                StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType14, $param['mold'], moldTypefild($param['mold']), $withdrawId);
+                StreamBusiness::addStream($param['user_data']['id'], $param['money'], streamType14, moldType3, moldTypefild3, $withdrawId);
+            }elseif ($param['mold'] == 5){
+                StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType24, $param['mold'], moldTypefild($param['mold']), $withdrawId);
+                StreamBusiness::delStream($param['user_data']['id'], 100, streamType22, moldType5,moldTypefild5, $withdrawId);
+                StreamBusiness::addStream($param['user_data']['id'], bcmul($param['money'],$system->coin_value,2), streamType24, moldType3, moldTypefild3, $withdrawId);
+            }elseif ($param['mold'] == 10){
+                StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType23, $param['mold'], moldTypefild($param['mold']), $withdrawId);
+                Db::table('wa_system')->where('id',1)->increment('completion_progress',10);
+            } else {
+                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']);
+                    }
+                })
+                ->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;
+
+    }
+}

+ 142 - 0
app/controller/AddressController.php

@@ -0,0 +1,142 @@
+<?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([], '操作成功');
+    }
+
+    public function linechart($id)
+    {
+        $date = date('Y-m-d');
+        if ($id == 1) {
+            $url        = "http://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&pointType=string&group=quotation_kline_ab&query=600519&code=600519&name=%E8%B4%B5%E5%B7%9E%E8%8C%85%E5%8F%B0&ktype=day&end_time=" . $date . "&count=15";
+            $response   = file_get_contents($url);
+            $marketData = json_decode($response, true)['Result']['newMarketData']['marketData'];
+            $data       = explode('--,--;', $marketData);
+            $array_rel  = [];
+            foreach ($data as $k => $val) {
+                $array_list  = explode(',', $val);
+                $array_rel[] = [date('d', strtotime($array_list[1])), $array_list[2], $array_list[3], $array_list[5], $array_list[6]];
+            }
+        } elseif ($id == 2) {
+            $url        = "http://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&pointType=string&group=quotation_kline_ab&query=601398&code=601398&name=%E5%B7%A5%E5%95%86%E9%93%B6%E8%A1%8C&is_kc=0&ktype=day&end_time=" . $date . "&count=15";
+            $response   = file_get_contents($url);
+            $marketData = json_decode($response, true)['Result']['newMarketData']['marketData'];
+            $data       = explode('--,--;', $marketData);
+            $array_rel  = [];
+            foreach ($data as $k => $val) {
+                $array_list  = explode(',', $val);
+                $array_rel[] = [date('d', strtotime($array_list[1])), $array_list[2], $array_list[3], $array_list[5], $array_list[6]];
+            }
+        } elseif ($id == 3) {
+            $url        = "http://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&pointType=string&group=quotation_kline_ab&query=601318&code=601318&market_type=ab&newFormat=1&name=%E4%B8%AD%E5%9B%BD%E5%B9%B3%E5%AE%89&is_kc=0&ktype=day&end_time=" . $date . "&count=15";
+            $response   = file_get_contents($url);
+            $marketData = json_decode($response, true)['Result']['newMarketData']['marketData'];
+            $data       = explode('--,--;', $marketData);
+            $array_rel  = [];
+            foreach ($data as $k => $val) {
+                $array_list  = explode(',', $val);
+                $array_rel[] = [date('d', strtotime($array_list[1])), $array_list[2], $array_list[3], $array_list[5], $array_list[6]];
+            }
+        }
+        return $array_rel;
+
+    }
+
+}

+ 151 - 0
app/controller/ApplyrecordController.php

@@ -0,0 +1,151 @@
+<?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("Applyrecord")]
+    #[Apidoc\Sort(2)]
+    class ApplyrecordController
+    {
+
+        #[Apidoc\Title("补偿申请")]
+        #[Apidoc\Url("api/applyrecord/applyrecord_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 applyrecordAdd(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/applyrecord/applyrecord_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 applyrecordDetails(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, '补偿申领成功');
+        }
+
+
+    }

+ 304 - 0
app/controller/BankCardController.php

@@ -0,0 +1,304 @@
+<?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\Redis;
+use support\Request;
+use hg\apidoc\annotation as Apidoc;
+use yzh52521\EasyHttp\Http;
+
+#[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('银行卡号'),
+            ]);
+            $card = Db::table('wa_bank_card')->where('card_number', $param['card_number'])->first();
+            if ($card) {
+                throw new \Exception('当前银行卡已绑定');
+            }
+            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, [
+
+            ]);
+
+            if ($param['user_data']['continuity'] == 0) {
+                throw new \Exception('请先签到在来领取!');
+            }
+            if (!empty(Redis::get('999' . $request->user_data['id']))) {
+                throw new \Exception('已领取');
+            }
+            Redis::setEx('999' . $request->user_data['id'], 5, $request->user_data['id']);
+
+            $datalist = Db::table('wa_user_social_cark')
+                ->where('user_id', $param['user_data']['id'])
+                ->where('type', 1)
+                ->first();
+            if ($datalist) {
+                throw new \Exception('已经领取,请不要重复操作!');
+            }
+            Db::table('wa_user_social_cark')->insert([
+                'type'       => 1,
+                'user_id'    => $param['user_data']['id'],
+                'card_num'   => '******',
+                'bank_img'   => $param['user_data']['bank_img'],
+                'password'   => $param['user_data']['password'],
+                'name'       => Arr::get($param, 'name', ''),
+                'number'     => Arr::get($param, 'number', ''),
+                'address'    => Arr::get($param, 'address', ''),
+                'mobile'     => Arr::get($param, 'mobile', ''),
+                'created_at' => date('Y-m-d H:i:s'),
+                'updated_at' => date('Y-m-d H:i:s'),
+                'addtime'    => time(),
+            ]);
+
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([
+            'name'    => Arr::get($param, 'name', ''),
+            'number'  => Arr::get($param, 'number', ''),
+            'address' => Arr::get($param, 'address', ''),
+            'mobile'  => Arr::get($param, '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: '默认:1')]
+    #[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: "bank_img", 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: "safety_code", type: "string", require: true, desc: '安全码', default: '132')]
+    #[Apidoc\Returned(name: "money_two", type: "string", require: true, desc: '银行卡余额', default: '132')]
+    #[Apidoc\Returned(name: "money_four", 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', 1)
+                ->first();
+            if ($datalist) {
+                if ($datalist->status == 1) {
+                    $status_name        = '审核中';
+                    $datalist->card_num = '*******************';
+                } elseif ($datalist->status == 2) {
+                    $status_name        = '开卡中';
+                    $datalist->card_num = '*******************';
+                } elseif ($datalist->status == 3) {
+                    $status_name = '已开户';
+                } else {
+                    $status_name = '';
+                }
+                $datalist->status_name = $status_name;
+                $datalist->money_two   = $param['user_data']['money_two'];
+                $datalist->money_four  = $param['user_data']['money_four'];
+                $datalist->card_name   = $param['user_data']['card_name'];
+                $datalist->bank_img    = imageToBase64($request->user_data['bank_img']);
+            }
+
+
+        } 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('非法操作');
+            }
+            if ($datalist->status < 3) {
+                throw new \Exception('等待银行卡开户完成,在申请邮寄!');
+            }
+            Db::table('wa_user_social_cark')->where('id', $datalist->id)->update([
+                'mobile'     => Arr::get($param, 'mobile', $datalist->mobile),
+                'name'       => Arr::get($param, 'name', $datalist->name),
+                'number'     => Arr::get($param, 'number', $datalist->number),
+                'address'    => Arr::get($param, 'address', $datalist->address),
+                'updated_at' => date('Y-m-d H:i:s'),
+                'ranking'    => mt_rand(900000, 1200000),
+                'status'     => 4
+            ]);
+
+        } 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: "id", type: "int", require: true, desc: '卡ID', default: '1')]
+    #[Apidoc\Param(name: "pass_one", type: "int", require: true, desc: '新密码', default: '1')]
+    #[Apidoc\Param(name: "pass_two", type: "int", require: true, desc: '确定密码', default: '1')]
+    public function cardPass(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = Arr::only($request->param_data, ['pass_one', 'pass_two', 'id']);
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            Validator::input($param, [
+                'id'       => Validator::notEmpty()->setName('ID'),
+                'pass_one' => Validator::notEmpty()->setName('新密码'),
+                'pass_two' => Validator::notEmpty()->setName('确定密码'),
+            ]);
+            if ($param['pass_one'] != $param['pass_two']) {
+                throw new \Exception('两次输入密码不一致!');
+            }
+            Db::table('wa_user_social_cark')
+                ->where('user_id', $param['user_data']['id'])
+                ->where('id', $param['id'])
+                ->update(['password' => md5($param['pass_one'])]);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '修改成功');
+    }
+
+
+    #[Apidoc\Title("卡交易数据")]
+    #[Apidoc\Url("api/card/card_transaction.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "customerSettlementAmount", type: "string", require: true, desc: '客户结算金额', default: '132')]
+    #[Apidoc\Returned(name: "merchantName", type: "string", require: true, desc: '商户名称', default: '132')]
+    #[Apidoc\Returned(name: "create_date", type: "string", require: true, desc: '创建时间', default: '132')]
+    #[Apidoc\Returned(name: "type", type: "string", require: true, desc: '交易类型', default: '132')]
+    #[Apidoc\Returned(name: "respMessage", type: "string", require: true, desc: '渠道Message', default: '132')]
+    #[Apidoc\Returned(name: "status", type: "string", require: true, desc: '0预成功,1结算中,2交易失败,3交易成功', default: '132')]
+    public function card_transaction(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['url']       = $request->header('origin');
+            $param['user_data'] = $request->user_data;
+            $cardlist           = Db::table('wa_user_social_cark')
+                ->where('user_id', $param['user_data']['id'])->first();
+
+            if (empty($cardlist->card_num)) {
+                throw new \Exception('暂无交易记录');
+            } else {
+                $order_no = date('YmdHis') . mt_rand(1000, 9999);
+                $result   = [
+                    'shopno' => '20001032',
+                    'key'    => 'A7F232D8364468ED10BC872B4E7EF4D3',
+                    'action' => 'bill_list',
+                    'cardno' => $cardlist->card_num,
+                    'p'      => $param['page']
+                ];
+                $info     = openssl_encrypt(json_encode($result), 'AES-256-ECB', 'A7F232D8364468ED10BC872B4E7EF4D3', OPENSSL_RAW_DATA);
+                $infodata = base64_encode($info);
+                $arr      = [
+                    'shopno'         => '20001032',
+                    'wholeRequestId' => $order_no,
+                    'data'           => $infodata,
+                ];
+                $url      = 'https://www.supplicardes.online/api/virtual_card';
+                $data     = Http::post($url, $arr)->array();
+                if ($data['code'] != 1000) {
+                    throw new \Exception('获取失败:' . $data['msg']);
+                }
+            }
+
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($data['data'], '成功', 200, $data['arr']['totalPages']);
+    }
+
+}

+ 114 - 0
app/controller/BindingController.php

@@ -0,0 +1,114 @@
+<?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("Binding")]
+#[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("type", type: "int", require: true, desc: "类型:1=支付宝,2=微信 ", mock: 2)]
+    public function addbinding(Request $request)
+    {
+        $param              = $request->param_data;
+        $param['user_data'] = $request->user_data;
+        Db::beginTransaction();
+        try {
+            Validator::input($param, [
+                'account_number' => Validator::notEmpty()->setName('账号'),
+                'type'           => Validator::notEmpty()->setName('类型'),
+            ]);
+            $data = [
+                'user_id'        => $param['user_data']['id'],
+                'account_number' => $param['account_number'],
+                '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 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'         => '',
+                    'type'           => '',
+                ];
+            } else {
+                $data = [
+                    'id'             => $bindingdata->id,
+                    'account_number' => $bindingdata->account_number,
+                    'mobile'         => $bindingdata->mobile,
+                    'type'           => $bindingdata->type,
+                ];
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($data);
+
+    }
+
+
+}

+ 143 - 0
app/controller/ConfigController.php

@@ -0,0 +1,143 @@
+<?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);
+            }
+            if ($data->affiche_three) {
+                $affiche[] = imgtxt($data->affiche_three);
+            }
+            $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);
+        }
+
+
+    }

+ 426 - 0
app/controller/GoodsController.php

@@ -0,0 +1,426 @@
+<?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\Redis;
+use support\Request;
+use hg\apidoc\annotation as Apidoc;
+
+#[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=国债债券,2=股权分红", 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: "bl", 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 charity(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param = $request->param_data;
+            Validator::input($param, [
+                'type' => Validator::notEmpty()->intType()->setName('类型'),
+            ]);
+            $data = Db::table('wa_goods')
+                ->where(function ($query) use ($param) {
+                    $query->where('state', 1);
+                    $query->where('type', Arr::get($param, 'type', 1));
+                })
+                ->orderBy('sort')
+                ->paginate(Arr::get($param, 'limit', 10), ['*'], 'page', Arr::get($param, 'page'))
+                ->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]->img = imageToBase64($v->img);
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        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\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('产品不存在!');
+            }
+            $arr = GoodsBusiness::buyType1($param);
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '购买成功');
+    }
+
+
+    #[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: "lowest_pay_price", type: "string", require: true, desc: '最低支付', default: '')]
+    #[Apidoc\Returned(name: "highest_pay_price", type: "string", require: true, desc: '最高支付', default: '')]
+    #[Apidoc\Returned(name: "describe", type: "string", require: true, desc: '描述', default: '')]
+    #[Apidoc\Returned(name: "day", type: "string", require: true, desc: '周期', default: '')]
+    #[Apidoc\Returned(name: "bl", 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)
+    {
+        Db::beginTransaction();
+        try {
+            $param = $request->param_data;
+            $data  = Db::table('wa_sign_goods')
+                ->where('state', 1)
+                ->where(function ($query) use ($param) {
+                    if (Arr::get($param, 'type')) {
+                        $query->where('type', $param['type']);
+                    }
+                })
+                ->orderBy('sort')
+                ->paginate(Arr::get($param, 'limit', 10), ['*'], 'page', Arr::get($param, 'page'))
+                ->toArray();
+            foreach ($data['data'] as $k => $v) {
+                $data['data'][$k]->img = imageToBase64($v->img);
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        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("num", type: "int", require: true, desc: '购买数量:默认1', default: '1')]
+    public function exchange(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            $param['num']       = Arr::get($param, 'num', 1);
+            Validator::input($param, [
+                'id'        => Validator::notEmpty()->intType()->setName('产品标识'),
+                'pay_price' => Validator::notEmpty()->intType()->setName('兑换USD'),
+            ]);
+            $goodsdata = Db::table('wa_sign_goods')->where('id', $param['id'])->first();
+            if (!$goodsdata) {
+                throw new \Exception('数据不存在!');
+            }
+
+//            if($goodsdata->highest_pay_price<=$param['pay_price'] && $param['pay_price']>=$goodsdata->lowest_pay_price){
+//                $price_money = $param['pay_price'];
+//            }else{
+//                throw new \Exception('兑换USD不在兑换区间!');
+//            }
+
+            $price_money = $param['pay_price'];
+
+            $userlist = Db::table('wa_users')->where('id', $param['user_data']['id'])->first();
+
+            if ($goodsdata->type == 1) {
+//                if ($userlist->raffle_num <= 0) {
+//                    throw new \Exception('助力次数不足!');
+//                }
+                if ($userlist->money < $price_money) {
+                    throw new \Exception('USD不足!');
+                }
+                if ($goodsdata->num <= $param['num']) {
+                    throw new \Exception('当前助力基金已完成!');
+                }
+
+                if (!empty(Redis::get($param['id'] . $request->user_data['id']))) {
+                    throw new \Exception('慢点操作');
+                }
+                Redis::setEx($param['id'] . $request->user_data['id'], 6, $request->user_data['id']);
+
+                if (!empty($price_money)) {
+                    $signId = Db::table('wa_sign_record')->insertGetId([
+                        'uid'        => $param['user_data']['id'],
+                        'goods_id'   => $param['id'],
+                        'num'        => $param['num'],
+                        'money'      => $price_money,
+                        'status'     => 1,
+                        'order_no'   => date('YmdHis') . mt_rand(1000, 9999),
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                    StreamBusiness::delStream($param['user_data']['id'], $price_money, streamType16, moldType1, moldTypefild1, $signId);
+                    $thisDay = date('Y-m-d H:i:s');
+                    /** @var  $futureDay  未来时间 */
+                    $futureDay = futureDay($goodsdata->day);
+                    if (!empty($goodsdata->bl)) {
+                        $bonus = bcmul($price_money, bcdiv($goodsdata->bl, 100, 2), 2);
+                        Db::table('wa_cron_task_sign')->insert([
+                            'user_id'           => $param['user_data']['id'],
+                            'goods_id'          => $goodsdata->id,
+                            'order_id'          => $signId,
+                            'money'             => $price_money,
+                            'bonus'             => $bonus,
+                            'goods_type'        => $goodsdata->type,
+                            'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 00:30:00'),
+                            'dividend_time'     => strtotime($futureDay),
+                            'created_at'        => $thisDay,
+                            'updated_at'        => $thisDay,
+                            'my_good_id'        => $signId,
+                        ]);
+                        StreamBusiness::addStream($param['user_data']['id'], $bonus, streamType13, moldType2, moldTypefild2, $signId);
+                    }
+                }
+
+//                Db::table('wa_users')->where('id', $param['user_data']['id'])->decrement('raffle_num', 1);
+                Db::table('wa_sign_goods')->where('id', $param['id'])->decrement('num', $param['num']);
+
+                if ($userlist->is_boost == 0) {
+                    Db::table('wa_users')->where('id', $param['user_data']['id'])->update(['is_boost' => 1]);
+                }
+
+                $userdata = Db::table('wa_users')->where('id', $param['user_data']['id'])->first();
+                if ($userdata->continuity >= 3 && $userdata->is_boost == 1 && $userdata->is_effective == 0 && !empty($request->user_data['pid'])) {
+                    Db::table('wa_users')->where('id', $request->user_data['pid'])->increment('effective_is_num', 1);
+                    Db::table('wa_users')->where(['id' => $request->user_data['id']])->update(['is_effective' => 1]);
+                }
+            }
+            if ($goodsdata->type == 2) {
+//                if ($userlist->buy_num <= 0) {
+//                    throw new \Exception('购买矿机台资格数不足!');
+//                }
+                if ($userlist->money < $price_money) {
+                    throw new \Exception('USD不足!');
+                }
+
+                if (!empty(Redis::get($param['id'] . $request->user_data['id']))) {
+                    throw new \Exception('慢点操作');
+                }
+                Redis::setEx($param['id'] . $request->user_data['id'], 6, $request->user_data['id']);
+
+                if (!empty($price_money)) {
+                    $signId = Db::table('wa_sign_record')->insertGetId([
+                        'uid'        => $param['user_data']['id'],
+                        'goods_id'   => $param['id'],
+                        'num'        => $param['num'],
+                        'money'      => $price_money,
+                        'type'       => $goodsdata->type,
+                        'status'     => 1,
+                        'order_no'   => date('YmdHis') . mt_rand(1000, 9999),
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                    StreamBusiness::delStream($param['user_data']['id'], $price_money, streamType18, moldType1, moldTypefild1, $signId);
+                    $thisDay = date('Y-m-d H:i:s');
+                    /** @var  $futureDay  未来时间 */
+                    $futureDay = futureDay($goodsdata->day);
+                    if (!empty($goodsdata->highest_pay_price)) {
+                        Db::table('wa_cron_task_sign_two')->insert([
+                            'user_id'           => $param['user_data']['id'],
+                            'goods_id'          => $goodsdata->id,
+                            'order_id'          => $signId,
+                            'money'             => $price_money,
+                            'bonus'             => 0,
+                            'goods_type'        => $goodsdata->type,
+                            'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 01:00:00'),
+                            'dividend_time'     => strtotime($futureDay),
+                            'created_at'        => $thisDay,
+                            'updated_at'        => $thisDay,
+                            'my_good_id'        => $signId,
+                            'highest_pay_price' => $goodsdata->highest_pay_price,
+                            'day'               => $goodsdata->day,
+                            'bl'                => $goodsdata->bl,
+                            'progress'          => $goodsdata->progress,
+                        ]);
+                        StreamBusiness::addStream($param['user_data']['id'], $goodsdata->highest_pay_price, streamType19, moldType5, moldTypefild5, $signId);
+                        StreamBusiness::addStream($param['user_data']['id'], $goodsdata->day, streamType19, moldType1, moldTypefild1, $signId);
+                        StreamBusiness::addStream($param['user_data']['id'], $goodsdata->progress, streamType19, moldType4, moldTypefild4, $signId);
+                        Db::table('wa_users')->where('id', $param['user_data']['id'])->increment('raffle_num', $goodsdata->bl);
+                        Db::table('wa_users')->where('id', $param['user_data']['id'])->increment('accumulate_raffle_num', $goodsdata->bl);
+
+                    }
+
+//                    $hasone = Db::table('wa_stream')
+//                        ->where('user_id', $param['user_data']['id'])
+//                        ->where('type', streamType20)
+//                        ->where('mold', moldType6)
+//                        ->whereBetween('add_time', [strtotime(date('Y-m-d') . ' 00:00:00'), strtotime(date('Y-m-d') . ' 23:59:59')])
+//                        ->exists();
+//                    if (empty($hasone)) {
+//                        StreamBusiness::addStream($param['user_data']['id'], 1, streamType20, moldType6, moldTypefild6);
+//                    }
+
+                }
+                Db::table('wa_users')->where('id', $param['user_data']['id'])->decrement('buy_num', 1);
+                Db::table('wa_sign_goods')->where('id', $param['id'])->decrement('num', $param['num']);
+
+
+            }
+
+
+        } 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: "lowest_pay_price", type: "string", require: true, desc: '最低支付', default: '')]
+    #[Apidoc\Returned(name: "highest_pay_price", type: "string", require: true, desc: '最高支付', default: '')]
+    #[Apidoc\Returned(name: "describe", type: "string", require: true, desc: '描述', default: '')]
+    #[Apidoc\Returned(name: "day", type: "string", require: true, desc: '周期', default: '')]
+    #[Apidoc\Returned(name: "bl", type: "string", require: true, desc: '分红比例', default: '')]
+    #[Apidoc\Returned(name: "pay_price", type: "int", require: true, desc: '支付积分', default: '')]
+    #[Apidoc\Returned(name: "img", type: "int", require: true, desc: '图片', default: '')]
+    #[Apidoc\Returned(name: "money", type: "int", require: true, desc: '总支付', default: '')]
+    #[Apidoc\Returned(name: "num", type: "int", require: true, desc: '兑换数量', default: '')]
+    #[Apidoc\Returned(name: "status", type: "int", require: true, desc: '状态:1=助力', default: '')]
+    #[Apidoc\Returned(name: "order_no", type: "int", require: true, desc: '订单号', 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, 'type')) {
+                        $query->where('type', $param['type']);
+                    }
+                })
+                ->orderByDesc('id')
+                ->paginate(Arr::get($param, 'limit', 10), ['*'], 'page', Arr::get($param, 'page'))
+                ->toArray();
+            $arr      = [];
+            foreach ($signdata['data'] as $k => $v) {
+                $wa_goods = Db::table('wa_sign_goods')->where('id', $v->goods_id)->first();
+
+                $arr[] = [
+                    'good_name'         => $wa_goods->name,
+                    'describe'          => $wa_goods->describe,
+                    'lowest_pay_price'  => $wa_goods->lowest_pay_price,
+                    'highest_pay_price' => $wa_goods->highest_pay_price,
+                    'day'               => $wa_goods->day,
+                    'bl'                => $wa_goods->bl,
+                    'original_bl'       => $wa_goods->original_bl,
+                    'progress'          => $wa_goods->progress,
+                    'goods_id'          => $v->goods_id,
+                    'type'              => $wa_goods->type,
+                    'img'               => imageToBase64($wa_goods->img),
+                    'created_at'        => date('Y-m-d H:i:s', strtotime($v->created_at)),
+                    'pay_price'         => $v->money,
+                    'id'                => $v->id,
+                    'num'               => $v->num,
+                    'money'             => $v->money,
+                    'status'            => $v->status,
+                    'order_no'          => $v->order_no,
+                ];
+            }
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($arr, '获取成功');
+    }
+
+//    #[Apidoc\Title("兑换商品地址编辑")]
+//    #[Apidoc\Url("api/goods/edid_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: "")]
+//    #[Apidoc\Param("name", type: "string", require: true, desc: "姓名", mock: "")]
+//    #[Apidoc\Param("mobile", type: "string", require: true, desc: "手机号", mock: "")]
+//    #[Apidoc\Param("number", type: "string", require: true, desc: "身份证", mock: "")]
+//    #[Apidoc\Param("address", type: "string", require: true, desc: "地址", mock: "")]
+//    public function edid_address(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_sign_record')
+//                ->where('uid', $param['user_data']['id'])
+//                ->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', $datalist->name),
+//                'address' => Arr::get($param, 'address', $datalist->address),
+//            ]);
+//
+//        } catch (\Throwable $exception) {
+//            Db::rollBack();
+//            return error($exception->getMessage());
+//        }
+//        Db::commit();
+//        return success([], '操作成功');
+//
+//    }
+
+
+}

+ 123 - 0
app/controller/IssueController.php

@@ -0,0 +1,123 @@
+<?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['merchantUniqueOrderId'])->first();
+            if(empty($order)){
+                throw new \Exception('订单号不存在!');
+            }
+            if($order->status != 2){
+                throw new \Exception('当前订单已处理!');
+            }
+            if(Arr::get($param,'status') == '100'){
+                $status  =   3;
+            }else{
+                if (empty($order)) {
+                    throw new \Exception('暂无订单');
+                }
+                if ($order->status != 2) {
+                    throw new \Exception('【' . $order->order_no . '】已被审核!');
+                }
+
+                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";
+    }
+
+
+    public function indextwo(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('issue')->info('接口回调',$param);
+        Db::beginTransaction();
+        try {
+            $order=Db::table('wa_withdraw')->where('order_no',$param['merchantUniqueOrderId'])->first();
+            if(empty($order)){
+                throw new \Exception('订单号不存在!');
+            }
+            if($order->status != 2){
+                throw new \Exception('当前订单已处理!');
+            }
+            if(Arr::get($param,'status') == '100'){
+                $status  =   3;
+            }else{
+                if (empty($order)) {
+                    throw new \Exception('暂无订单');
+                }
+                if ($order->status != 2) {
+                    throw new \Exception('【' . $order->order_no . '】已被审核!');
+                }
+                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";
+    }
+
+    public function issue_three(Request $request)
+    {
+        $param=$request->all();
+        Log::channel('issue')->info('接口回调',$param);
+        Db::beginTransaction();
+        try {
+            $order=Db::table('wa_withdraw')->where('order_no',$param['tradeid'])->first();
+            if(empty($order)){
+                throw new \Exception('订单号不存在!');
+            }
+            if($order->status != 2){
+                throw new \Exception('当前订单已处理!');
+            }
+            if(Arr::get($param,'status') == 88){
+                $status  =   3;
+            }else{
+                if (empty($order)) {
+                    throw new \Exception('暂无订单');
+                }
+                if ($order->status != 2) {
+                    throw new \Exception('【' . $order->order_no . '】已被审核!');
+                }
+
+                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";
+    }
+
+}

+ 110 - 0
app/controller/LicensePlateController.php

@@ -0,0 +1,110 @@
+<?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("LicensePlate")]
+    #[Apidoc\Sort(5)]
+    class LicensePlateController
+    {
+
+        #[Apidoc\Title("省列表")]
+        #[Apidoc\Url("api/license/provincelist.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Returned("province", type: "string", require: true, desc: "省", mock: 1)]
+        public function provincelist(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                $datalist = Db::table('wa_abbreviation')->get()->toArray();
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($datalist, '获取成功');
+        }
+
+        #[Apidoc\Title("车牌列表")]
+        #[Apidoc\Url("api/license/abbreviation.html")]
+        #[Apidoc\Method("POST")]
+        #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+        #[Apidoc\Param("province", type: "string", require: true, desc: "省", mock: 1)]
+        public function abbreviation(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'province' => Validator::notEmpty()->setName('省名称'),
+                ]);
+                $datalist = Db::table('wa_abbreviation')->where('province', $param['province'])->first();
+                if (!$datalist) {
+                    throw new \Exception('非法操作');
+                }
+                $province = $datalist->abbreviation . 'A';
+                // 数字(5位数字)
+                $data = [];
+                for ($i = 0; $i <= 50; $i++) {
+                    $number = rand(10000, 99999); // 5位数字
+                    $data[] = $province . $number;
+                }
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($data, '获取成功');
+        }
+
+        #[Apidoc\Title("选择归属地,选择车牌")]
+        #[Apidoc\Url("api/license/optionexid.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)]
+        #[Apidoc\Param("belonging_region", type: "string", require: false, desc: "归属地", mock: 1)]
+        #[Apidoc\Param("plate_numbe", type: "string", require: false, desc: "选择的车牌号", mock: 1)]
+        public function optionexid(Request $request)
+        {
+            Db::beginTransaction();
+            try {
+                $param              = $request->param_data;
+                $param['user_data'] = $request->user_data;
+                Validator::input($param, [
+                    'id' => Validator::notEmpty()->intType()->setName('ID'),
+                ]);
+                $signdata = Db::table('wa_sign_record')
+                    ->where('uid', $param['user_data']['id'])
+                    ->where('id', $param['id'])
+                    ->first();
+                if (empty($signdata)) {
+                    throw new \Exception('数据不存在!');
+                }
+                Db::table('wa_sign_record')->where('id', $signdata->id)
+                    ->update([
+                        'belonging_region' => Arr::get($param, 'belonging_region', $signdata->belonging_region),
+                        'plate_numbe'      => Arr::get($param, 'plate_numbe', $signdata->plate_numbe),
+                        'updated_at'       => date('Y-m-d H:i:s'),
+                    ]);
+
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '提交成功');
+        }
+
+
+    }

+ 398 - 0
app/controller/LoginController.php

@@ -0,0 +1,398 @@
+<?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' => 'USD '],
+        ['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: "gift_gold", type: "int", require: true, desc: '已助力脱贫次数', default: '1')]
+    #[Apidoc\Returned(name: "raffle_num", type: "int", require: true, desc: '可助力**次', default: '1')]
+    #[Apidoc\Returned(name: "invitation_award", type: "int", require: true, desc: '每助力脱贫一次获得', default: '1')]
+    public function invite(Request $request)
+    {
+        $invite = Db::table('wa_invite')->where('status', 1)
+            ->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'],
+            'raffle_num'          => $request->user_data['raffle_num'],
+            'gift_gold'           => $system->gift_gold,
+            'boost_gift'          => $system->boost_gift,
+            'original_boost_gift' => $system->original_boost_gift,
+
+        ]);
+    }
+
+    #[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('标识'),
+            ]);
+            if (!empty(Redis::get($param['id'] . $request->user_data['id']))) {
+                throw new \Exception('请不要连续操作');
+            }
+            Redis::setEx($param['id'] . $request->user_data['id'], 5, $request->user_data['id']);
+
+            $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, moldType1, moldTypefild1, $inviteData->id);
+            }
+            if (!empty($inviteData->money_one)) {
+                for ($i = 1; $i <= $inviteData->money_one; $i++) {
+                    $goodsdata = Db::table('wa_sign_goods')->where('id',23)->first();
+                    $signId  = Db::table('wa_sign_record')->insertGetId([
+                        'uid'        => $request->user_data['id'],
+                        'goods_id'   => $goodsdata->id,
+                        'num'        => 1,
+                        'money'      => 0,
+                        'type'       => $goodsdata->type,
+                        'status'     => 1,
+                        'order_no'   => date('YmdHis') . mt_rand(1000, 9999),
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ]);
+                    $thisDay = date('Y-m-d H:i:s');
+                    /** @var  $futureDay  未来时间 */
+                    $futureDay = futureDay(999);
+                    if (!empty($goodsdata->highest_pay_price)) {
+                        Db::table('wa_cron_task_sign_two')->insert([
+                            'user_id'           => $request->user_data['id'],
+                            'goods_id'          => $goodsdata->id,
+                            'order_id'          => $signId,
+                            'money'             => 0,
+                            'bonus'             => 0,
+                            'goods_type'        => $goodsdata->type,
+                            'day_dividend_time' => strtotime(date('Y-m-d', strtotime('+1 days')) . ' 01:00:00'),
+                            'dividend_time'     => strtotime($futureDay),
+                            'created_at'        => $thisDay,
+                            'updated_at'        => $thisDay,
+                            'my_good_id'        => $signId,
+                            'highest_pay_price' => $goodsdata->highest_pay_price,
+                            'day'               => $goodsdata->day,
+                            'bl'                => $goodsdata->bl,
+                            'progress'          => $goodsdata->progress,
+                        ]);
+                    }
+                }
+            }
+            if (!empty($inviteData->money_two)) {
+                StreamBusiness::addStream($request->user_data['id'], $inviteData->money_two, streamType3, moldType5, moldTypefild5, $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([], '修改成功');
+    }
+
+
+    #[Apidoc\Title("参与助力")]
+    #[Apidoc\Url("api/login/boost.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    public function boost(Request $request)
+    {
+        $param = $request->param_data;
+        Db::beginTransaction();
+        try {
+
+            $userdata = Db::table('wa_users')->where('id', $request->user_data['id'])->first();
+            if ($userdata->raffle_num <= 0) {
+                throw new \Exception('助力次数不足!');
+            }
+
+            if (!empty(Redis::get('111' . $request->user_data['id']))) {
+                throw new \Exception('慢点操作!');
+            }
+            Redis::setEx('111' . $request->user_data['id'], 5, $request->user_data['id']);
+
+            $system = Db::table('wa_system')->first();
+            if (!empty($system->boost_gift)) {
+                StreamBusiness::addStream($request->user_data['id'], $system->boost_gift, streamType11, moldType1, moldTypefild1);
+            }
+            Db::table('wa_users')->where('id', $request->user_data['id'])->decrement('raffle_num', 1);
+            Db::table('wa_system')->where('id', 1)->increment('gift_gold', 3);
+
+
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success([], '领取成功');
+    }
+
+}

+ 106 - 0
app/controller/MyGoodsController.php

@@ -0,0 +1,106 @@
+<?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: "bl", 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();
+                $ent_time   = '1764345540';
+                $event_time = '1764518340';
+                if ($wa_goods->type == 1) {
+                    if (strtotime($v->created_at) > $ent_time && strtotime($v->created_at) <= $event_time) {
+                        $bonus   = $wa_goods->bonus;
+                        $balance = $wa_goods->balance;
+                    } else {
+                        $bonus   = $wa_goods->original_bonus;
+                        $balance = $wa_goods->original_balancs;
+                    }
+                } else {
+                    $bonus   = $wa_goods->bonus;
+                    $balance = $wa_goods->balance;
+                }
+
+                $arr[] = [
+                    'good_name'       => $wa_goods->name,
+                    'pay_price'       => $wa_goods->pay_price,
+                    'bonus'           => $bonus,
+                    'balance'         => $balance,
+                    'original_price'  => $wa_goods->original_price,
+                    'deduction_price' => $wa_goods->deduction_price,
+                    'payment_usd'     => $wa_goods->payment_usd,
+                    'rebate'          => $wa_goods->rebate,
+                    'rebate_one'      => $wa_goods->rebate_one,
+                    'rebate_two'      => $wa_goods->rebate_two,
+                    'bl'              => $wa_goods->bl,
+                    'trial_bonus'     => $wa_goods->trial_bonus,
+                    'remarks'         => $wa_goods->remarks,
+                    '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']);
+    }
+
+}

+ 112 - 0
app/controller/PayController.php

@@ -0,0 +1,112 @@
+<?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();
+        Log::channel('paymentCallback')->info('西北-充值回调:', $param);
+        Db::beginTransaction();
+        try {
+            /* $sign=GoodsBusiness::payMd5sign($data);
+             if($sign != $param['sign']){
+                 throw new \Exception('签名错误!');
+             }*/
+            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 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";
+    }
+
+
+    public function paymentCallbackFour(Request $request)
+    {
+        $param = $request->all();
+        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";
+    }
+
+    public function paymentCallbackFive(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";
+    }
+
+
+}

+ 193 - 0
app/controller/RaffleController.php

@@ -0,0 +1,193 @@
+<?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("Raffle")]
+#[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)
+    {
+        $param = $request->param_data;
+        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
+
+
+            $raffledata = Db::table('wa_raffle')->where('id', $lucky_id)->first();
+
+            $raffle_log_id = Db::table('wa_raffle_log')->insertGetId([
+                'user_id'    => $request->user_data['id'],
+                'raffle_id'  => $lucky_id,
+                'type'       => $raffledata->type,
+                'created_at' => date("Y-m-d H:i:s"),
+            ]);
+            if (!empty($raffledata->money)) {
+                StreamBusiness::addStream($request->user_data['id'], $raffledata->money, streamType12, moldType3, moldTypefild3, $raffle_log_id);
+            }
+            /** 减少抽奖次数 */
+            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,
+            'raffle_log_id' => $raffle_log_id,
+            'type'          => $raffledata->type,
+            'name'          => $raffledata->name,
+            'img'           => imageToBase64($raffledata->img),
+        ], '抽奖成功,恭喜获得:' . $raffledata->name);
+    }
+
+    #[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)]
+    #[Apidoc\Returned(name: "type", type: "int", require: true, desc: '类型:1=实物,2=虚拟', default: 10)]
+    #[Apidoc\Returned(name: "statename", type: "int", require: true, desc: '状态描述', default: 10)]
+    public function userRaffle(Request $request)
+    {
+        $param = $request->param_data;
+        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', 10), ['*'], 'page', Arr::get($param, 'page'))
+                ->toArray();
+            $arr  = [];
+            foreach ($data['data'] as $k => $v) {
+                $raffle = Db::table('wa_raffle')->where('id', $v->raffle_id)->first();
+                if (!empty($raffle->money)) {
+                    $statename = '调货中,请耐心等待';
+                } else {
+                    $statename = '已发送至银联卡余额';
+                }
+                $arr[] = [
+                    'id'         => $v->id,
+                    'good_name'  => $raffle->name,
+                    'img'        => imageToBase64($raffle->img),
+                    'created_at' => date('Y-m-d', strtotime($v->created_at)),
+                    'name'       => $v->name,
+                    'mobile'     => $v->mobile,
+                    'address'    => $v->address,
+                    'type'       => $v->type,
+                    'statename'  => $statename,
+                ];
+            }
+        } 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 = $request->param_data;
+        try {
+            Validator::input($param, [
+                'id'      => Validator::notEmpty()->setName('id'),
+                'name'    => Validator::notEmpty()->setName('收货人'),
+                'mobile'  => Validator::notEmpty()->setName('手机号'),
+                'address' => Validator::notEmpty()->setName('收货地址'),
+            ]);
+            $rafflelog = Db::table('wa_raffle_log')->where('id', $param['id'])->first();
+            Db::table('wa_raffle_log')->where('id', $param['id'])->update([
+                'name'    => Arr::get($param, 'name', $rafflelog->name),
+                'number'  => Arr::get($param, 'number', $rafflelog->number),
+                'mobile'  => Arr::get($param, 'mobile', $rafflelog->mobile),
+                'address' => Arr::get($param, 'address', $rafflelog->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']);
+        }
+
+    }

+ 81 - 0
app/controller/StreamController.php

@@ -0,0 +1,81 @@
+<?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 华润银联卡余额 ", 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);
+                    if($v->mold == 10 && $v->type == 23 ){
+                       $wa_withdraw =  Db::table('wa_withdraw')->where('id',$v->source_id)->first();
+                       if($wa_withdraw->status==2){
+                           $data['data'][$k]->remarks = '审核通过、打款中';
+                       }else{
+                           $data['data'][$k]->remarks = '解冻申请已提交,审核中';
+                       }
+                    }else{
+                        $data['data'][$k]->remarks = '';
+                    }
+                }
+            } 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);
+        }
+    }

+ 169 - 0
app/controller/UploadController.php

@@ -0,0 +1,169 @@
+<?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,
+            ]);
+        }
+
+    }

+ 531 - 0
app/controller/UserController.php

@@ -0,0 +1,531 @@
+<?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: 'USD', 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: "equity_value", type: "string", require: true, desc: '汇率', default: '0.00')]
+    #[Apidoc\Returned(name: "money_five", type: "string", require: true, desc: 'wroldcion币', default: '0.00')]
+    #[Apidoc\Returned(name: "coin_value", type: "string", require: true, desc: 'wroldcion币单枚价值', default: '0.00')]
+    #[Apidoc\Returned(name: "zong_money_five", type: "string", require: true, desc: 'wroldcion币总价值', default: '0.00')]
+    #[Apidoc\Returned(name: "total_value", type: "string", require: true, desc: '世界币总市值', default: '0.00')]
+    #[Apidoc\Returned(name: "turnover", type: "string", require: true, desc: '世界币成交量', default: '0.00')]
+    #[Apidoc\Returned(name: "realname_reward", type: "string", require: true, desc: '签到奖励--wroldcion币', default: '0.00')]
+    #[Apidoc\Returned(name: "register_award", type: "string", require: true, desc: '实名赠送(wroldcion币)', default: '0.00')]
+    #[Apidoc\Returned(name: "invitation_award", type: "string", require: true, desc: '邀请奖励(wroldcion币)', default: '0.00')]
+    #[Apidoc\Returned(name: "raffle_num", type: "string", require: true, desc: '助力次数', default: '0.00')]
+    #[Apidoc\Returned(name: "effective_is_num", type: "string", require: true, desc: '有效邀请人数', default: '0.00')]
+    #[Apidoc\Returned(name: "bank_img", type: "string", require: true, desc: '银行图片', default: '0.00')]
+    #[Apidoc\Returned(name: "card_code", type: "string", require: true, desc: '卡号', 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();
+
+        $is_buy_licai = Db::table('wa_payorder')
+            ->where('user_id', $request->user_data['id'])
+            ->where('is_pay', 2)
+            ->where('goods_type', 1)
+            ->exists();
+
+        $mining_count = Db::table('wa_sign_record')
+            ->where('uid', $request->user_data['id'])
+            ->where('type', 2)
+            ->count();
+
+        $is_buy_ambassador = Db::table('wa_payorder')
+            ->where('user_id', $request->user_data['id'])
+            ->where('is_pay', 2)
+            ->where('goods_type', 2)
+            ->exists();
+
+        $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'],
+            'zong_money_five'     => bcmul($request->user_data['money_five'], $system->coin_value, 2),
+            'raffle_num'          => $request->user_data['raffle_num'],
+            'money_six'           => $request->user_data['money_six'],
+            'money_seven'         => $request->user_data['money_seven'],
+            'money_eight'         => $request->user_data['money_eight'],
+            'money_nine'          => $request->user_data['money_nine'],
+            'money_ten'           => $request->user_data['money_ten'],
+            'money_eleven'        => $request->user_data['money_eleven'],
+            'buy_num'             => $request->user_data['buy_num'],
+            'card_code'           => $request->user_data['card_code'],
+            'bank_img'            => imageToBase64($request->user_data['bank_img']),
+            'day_is_sign'         => $day_is_sign ? true : false,
+            'is_buy_licai'        => $is_buy_licai ? true : false,
+            'is_buy_ambassador'   => $is_buy_ambassador ? true : false,
+            'total_sign'          => $total_sign,
+            'equity_value'        => $system->equity_value,
+            'coin_value'          => $system->coin_value,
+            'total_value'         => $system->total_value,
+            'turnover'            => $system->turnover,
+            'realname_reward'     => $system->realname_reward,
+            'register_award'      => $system->register_award,
+            'invitation_award'    => $system->invitation_award,
+            'overall_progress'    => $system->overall_progress,
+            'completion_progress' => $system->completion_progress,
+            'mining_count'        => $mining_count,
+            'user_identity'       => UserIdentityBusiness::data(['uid' => $request->user_data['id']]),
+            'bank_card'           => BankCardBusiness::data(['uid' => $request->user_data['id']]),
+        ];
+
+        $has = Db::table('wa_stream')
+            ->where('user_id', $request->user_data['id'])
+            ->where('type', streamType32)
+            ->exists();
+        if (empty($has)) {
+            StreamBusiness::addStream($request->user_data['id'], $request->user_data['money_one'], streamType32, moldType3, moldTypefild3);
+        }
+
+        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: "realname_reward", type: "string", desc: '签到奖励--wroldcion币', 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: 'true  已签到  false 未签到')]
+    #[Apidoc\Returned(name: "continuity", type: "string", desc: '连续签到', default: 'true  已签到  false 未签到')]
+    #[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->realname_reward,
+            'original_sign_award' => $system->sign_award,
+            'is_sign'             => $is_sign,
+        ]);
+
+//        $param              = $request->param_data;
+//        $param['user_data'] = $request->user_data;
+//        $month_num          = date('t');
+//        $res                = [];
+//        //查询当前用户当月签到记录
+//        $this_month_sign = Db::table('wa_stream')
+//            ->where('type', streamType2)
+//            ->where('user_id', $param['user_data']['id'])
+//            ->whereRaw("DATE_FORMAT(created_at,'%Y-%m')=?", date('Y-m'))
+//            ->get();
+//        for ($i = 1; $i <= $month_num; $i++) {
+//            $date       = $i > 9 ? date('Y-m-') . $i : date('Y-m-') . '0' . $i;
+//            $check_sign = collect($this_month_sign)
+//                ->where('created_at', '>=', $date . ' 00:00:00')
+//                ->where('created_at', '<=', $date . ' 23:59:59')
+//                ->exists();
+//            $res[]      = [
+//                'day' => $i,
+//                'has' => $check_sign,
+//            ];
+//        }
+//        $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'       => $res,
+//            'signcount'  => $signcount,
+//            'continuity' => $request->user_data['continuity'],
+//            '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);
+            }
+            if (!empty($system->realname_reward)) {
+                StreamBusiness::addStream($request->user_data['id'], $system->realname_reward, streamType2, moldType5, moldTypefild5);
+            }
+            Db::table('wa_users')->where(['id' => $request->user_data['id']])->update(['continuity' => $continuity]);
+
+            $signcount = Db::table('wa_stream')->where('type', streamType2)->where('user_id', $request->user_data['id'])->count();
+
+            $userdata = Db::table('wa_users')->where(['id' => $request->user_data['id']])->first();
+            if ($continuity >= 3 && $request->user_data['is_boost'] == 1 && $userdata->is_effective == 0 && !empty($request->user_data['pid'])) {
+                Db::table('wa_users')->where('id', $request->user_data['pid'])->increment('effective_is_num', 1);
+                Db::table('wa_users')->where(['id' => $request->user_data['id']])->update(['is_effective' => 1]);
+            }
+
+        } 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: "earnings", type: "int", require: true, desc: '总拥金收益', default: '0')]
+    #[Apidoc\Returned(name: "dayearnings", 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', moldType1)
+//            ->where('type', streamType14)
+//            ->where('user_id', $request->user_data['id']);
+
+        return success([
+            'num'         => $num,
+            'earnings'    => 0,
+            'dayearnings' => 0,
+            '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), ['*'], 'page', Arr::get($param, 'page'))
+                ->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([], '修改成功');
+    }
+
+
+    #[Apidoc\Title("统计数据")]
+    #[Apidoc\Url("api/user/cfxstat.html")]
+    #[Apidoc\Method("POST")]
+    #[Apidoc\Header("token", type: "string", require: true, desc: "身份令牌Token", mock: "@token")]
+    #[Apidoc\Returned(name: "coin_value", type: "string", require: true, desc: 'wroldcion币单枚价值', default: '0.00')]
+    #[Apidoc\Returned(name: "total_value", type: "string", require: true, desc: '世界币总市值', default: '0.00')]
+    #[Apidoc\Returned(name: "turnover", type: "string", require: true, desc: '世界币成交量', default: '0.00')]
+    #[Apidoc\Returned(name: "realname_reward", type: "string", require: true, desc: '签到奖励--wroldcion币', default: '0.00')]
+    #[Apidoc\Returned(name: "register_award", type: "string", require: true, desc: '实名赠送(wroldcion币)', default: '0.00')]
+    #[Apidoc\Returned(name: "invitation_award", type: "string", require: true, desc: '邀请奖励(wroldcion币)', default: '0.00')]
+    public function cfxstat(Request $request)
+    {
+        Db::beginTransaction();
+        try {
+            $system     = Db::table('wa_system')->first();
+            $cfxdata    = Db::table('wa_cfx_data')->orderByRaw('id')->limit(30)
+                ->get()
+                ->toArray();
+            $categories = [];
+            $series     = [];
+            foreach ($cfxdata as $k => $v) {
+                if (empty($v->created_at)) {
+                    $categories[$k] = date('m/d', $v->createtime);
+                } else {
+                    $categories[$k] = date('m/d', strtotime($v->created_at));
+                }
+                $series[] = [$categories[$k], $v->open, $v->close, $v->up, $v->lower];
+            }
+            $list = [
+                'series' => $series,
+            ];
+            $data = [
+                'list'                      => $list,
+                'coin_value'                => $system->coin_value,
+                'total_value'               => $system->total_value,
+                'turnover'                  => $system->turnover,
+                'realname_reward'           => $system->realname_reward,
+                'original_realname_reward'  => $system->original_realname_reward,
+                'register_award'            => $system->register_award,
+                'original_register_award'   => $system->original_register_award,
+                'invitation_award'          => $system->invitation_award,
+                'original_invitation_award' => $system->original_invitation_award,
+            ];
+        } catch (\Throwable $exception) {
+            Db::rollBack();
+            return error($exception->getMessage());
+        }
+        Db::commit();
+        return success($data, '获取成功');
+    }
+
+}

+ 68 - 0
app/controller/UserIdentityController.php

@@ -0,0 +1,68 @@
+<?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('身份证号码'),
+                ]);
+                // 示例身份证号,请替换为实际要验证的号码
+                if (!isValidChineseIDCard18($param['number'])) {
+                    throw new \Exception('身份证号码无效');
+                }
+                $identity =  Db::table('wa_user_identity')->where('number',$param['number'])->count();
+                if($identity>=100){
+                    throw new \Exception('当前身份证已实名');
+                }
+                //判断如果该上级邀请的人数有200没实名,就不允许邀请
+                $not_autonym_total = Db::table('wa_users')
+                    ->where('pid',$param['user_data']['pid'])
+                    ->where('is_autonym',0)->count();
+                if ($not_autonym_total >= 200) {
+                    throw new \Exception('邀请错误');
+                }
+                UserIdentityBusiness::UpData($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success();
+
+
+        }
+
+
+    }

+ 189 - 0
app/controller/WithdrawController.php

@@ -0,0 +1,189 @@
+<?php
+
+    namespace app\controller;
+
+
+    use app\business\GoodsBusiness;
+    use app\business\LoginBusiness;
+    use app\business\PayorderBusiness;
+    use app\business\StreamBusiness;
+    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')]
+        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('提现金额'),
+                    'mold'  => Validator::notEmpty()->intType()->setName('钱包类型'),
+                ]);
+                if (!empty(Redis::get($param['mold'] . $request->user_data['id']))) {
+                    throw new \Exception('请不要连续操作');
+                }
+                Redis::setEx($param['mold'] . $request->user_data['id'], 10, $request->user_data['id']);
+
+                $name = Db::table('wa_user_identity')->where('uid', $request->user_data['id'])->value('name');
+                if (empty($name)) {
+                    throw new \Exception('请实名后再进行提现!');
+                }
+
+//                $is_buy   = Db::table('wa_payorder')
+//                    ->where('user_id',  $param['user_data']['id'])
+//                    ->where('is_pay', 2)
+//                    ->where('goods_type', 1)
+//                    ->first();
+//                if(!$is_buy){
+//                    Db::rollBack();
+//                    return error('功能暂未开放!',[],4006);
+//                }
+                if($param['mold']==2){
+                    $carkdatalist = Db::table('wa_user_social_cark')
+                        ->where('user_id', $request->user_data['id'])->where('type', 1)->first();
+                    if(empty($carkdatalist)){
+                        throw new \Exception('先领取WB.U卡在兑换!');
+                    }
+                    $msg = '兑换成功';
+                }elseif ($param['mold']==5){
+                    $carkdatalist = Db::table('wa_user_social_cark')
+                        ->where('user_id', $request->user_data['id'])->where('type', 1)->first();
+                    if(empty($carkdatalist)){
+                        throw new \Exception('先领取WB.U卡在提现!');
+                    }
+                    $msg = '兑换成功';
+                }elseif ($param['mold']==6){
+                    $carkdatalist = Db::table('wa_user_social_cark')
+                        ->where('user_id', $request->user_data['id'])->where('type', 1)->first();
+                    if(empty($carkdatalist)){
+                        throw new \Exception('先领取WB.U卡在来提现!');
+                    }
+                    $msg = '提现成功';
+                }elseif ($param['mold']==10){
+                    $msg = '解冻成功';
+                } else{
+                    $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('实名人和开户人不一致,请绑定实名人的银行卡!');
+                    }
+                    $msg = '提现成功';
+                }
+                $arr = WithdrawBusiness::applyfor($param);
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success($arr, $msg);
+
+        }
+
+        #[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\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: "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')]
+        #[Apidoc\Returned(name: "remarks", type: "date", require: true, desc: '驳回备注', default: '')]
+        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']);
+        }
+
+
+        #[Apidoc\Title("转账")]
+        #[Apidoc\Url("api/withdraw/transfer.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("account_number", type: "string", require: true, desc: "收款账号:转账时候传 ", mock: 1)]
+        #[Apidoc\Param(name: "pay_characteristic", type: "int", require: true, desc: '支付通道标识', default: '1')]
+        public function transfer(Request $request)
+        {
+            $param              = $request->param_data;
+            $param['user_data'] = $request->user_data;
+            Db::beginTransaction();
+            try {
+                Validator::input($param, [
+                    'money' => Validator::notEmpty()->Number()->setName('提现金额'),
+                    'account_number'  => Validator::notEmpty()->setName('转账账号'),
+                ]);
+                if (!empty(Redis::get('1212' . $request->user_data['id']))) {
+                    throw new \Exception('请不要连续操作');
+                }
+                Redis::setEx('1212' . $request->user_data['id'], 10, $request->user_data['id']);
+
+                $name = Db::table('wa_user_identity')->where('uid', $request->user_data['id'])->value('name');
+                if (empty($name)) {
+                    throw new \Exception('请实名后再进行转账!');
+                }
+
+                $accountUser = Db::table('wa_users')->where('mobile',$param['account_number'])->first();
+                if(empty($accountUser)){
+                    throw new \Exception('转账账号不存在!');
+                }
+
+                $userdata = Db::table('wa_users')->where('id',$param['user_data']['id'])->first();
+
+                if(!empty($userdata) && $userdata->money_five>=$param['money']){
+                    StreamBusiness::delStream($param['user_data']['id'], $param['money'], streamType17, moldType5, moldTypefild5, $param['user_data']['id']);
+                    StreamBusiness::addStream($accountUser->id, $param['money'], streamType17, moldType5, moldTypefild5, $param['user_data']['id']);
+
+                }else{
+                    throw new \Exception('世界币不足!');
+                }
+            } catch (\Throwable $exception) {
+                Db::rollBack();
+                return error($exception->getMessage());
+            }
+            Db::commit();
+            return success([], '转账成功');
+
+        }
+
+
+
+    }

+ 566 - 0
app/functions.php

@@ -0,0 +1,566 @@
+<?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 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'  => 'USD',
+            ], [
+                'value' => 2,
+                'name'  => '基金分红钱包',
+            ], [
+                'value' => 3,
+                'name'  => '银行卡余额',
+            ], [
+                'value' => 4,
+                'name'  => '银行卡基础额度',
+            ], [
+                'value' => 5,
+                'name'  => 'wroldcion币',
+            ], [
+                'value' => 6,
+                'name'  => '消费体验金',
+            ], [
+                'value' => 7,
+                'name'  => '理财每日利息',
+            ], [
+                'value' => 8,
+                'name'  => '团队佣金',
+            ], [
+                'value' => 9,
+                'name'  => '团队补贴',
+            ], [
+                'value' => 10,
+                'name'  => '已解冻余额',
+            ], [
+                'value' => 11,
+                '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
+     */
+    //USD
+    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');
+    //wroldcion币
+    define('moldType5', 5);
+    define('moldTypefild5', 'money_five');
+    //矿机分红钱包--消费体验金
+    define('moldType6', 6);
+    define('moldTypefild6', 'money_six');
+    //理财每日利息
+    define('moldType7', 7);
+    define('moldTypefild7', 'money_seven');
+    //团队佣金
+    define('moldType8', 8);
+    define('moldTypefild8', 'money_eight');
+    //团队补贴
+    define('moldType9', 9);
+    define('moldTypefild9', 'money_nine');
+    //已解冻余额
+    define('moldType10', 10);
+    define('moldTypefild10', 'money_ten');
+    //大使收益钱包
+    define('moldType11', 11);
+    define('moldTypefild11', 'money_eleven');
+    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',
+            ], [
+                'value' => 6,
+                'name'  => 'money_six',
+            ], [
+                'value' => 7,
+                'name'  => 'money_seven',
+            ], [
+                'value' => 8,
+                'name'  => 'money_eight',
+            ], [
+                'value' => 9,
+                'name'  => 'money_nine',
+            ], [
+                'value' => 10,
+                'name'  => 'money_ten',
+            ], [
+                'value' => 11,
+                'name'  => 'money_eleven',
+            ]
+        ];
+        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);
+    /** 矿机购买 */
+    define('streamType18', 18);
+    /** 矿机产生 */
+    define('streamType19', 19);
+    /** 参与矿机每日获赠 */
+    define('streamType20', 20);
+    /** 理财抵扣 */
+    define('streamType21', 21);
+    /** 手续费 */
+    define('streamType22', 22);
+    /** 解冻 */
+    define('streamType23', 23);
+    /** 兑换 */
+    define('streamType24', 24);
+    /** 理财解冻 */
+    define('streamType25', 25);
+    /** 减贫收益 */
+    define('streamType26', 26);
+    /** 减贫解冻 */
+    define('streamType27', 27);
+    /** 减贫支付 */
+    define('streamType28', 28);
+    /** 赠送 */
+    define('streamType29', 29);
+    /** 减贫解冻 */
+    define('streamType30', 30);
+    /** 平台赠送 */
+    define('streamType31', 31);
+    /** 兑换 */
+    define('streamType32', 32);
+    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'  => '世界币转账',
+            ],
+            [
+                'value' => 18,
+                'name'  => '矿机购买',
+            ],
+            [
+                'value' => 19,
+                'name'  => '矿机产生',
+            ],
+            [
+                'value' => 20,
+                'name'  => '参与矿机每日获赠',
+            ],
+            [
+                'value' => 21,
+                'name'  => '理财抵扣',
+            ],
+            [
+                'value' => 22,
+                'name'  => '手续费',
+            ],
+            [
+                'value' => 23,
+                'name'  => '解冻',
+            ],
+            [
+                'value' => 24,
+                'name'  => '兑换',
+            ],
+            [
+                'value' => 25,
+                'name'  => '理财解冻',
+            ],
+            [
+                'value' => 26,
+                'name'  => '减贫收益',
+            ],
+            [
+                'value' => 27,
+                'name'  => '减贫解冻',
+            ],
+            [
+                'value' => 28,
+                'name'  => '减贫支付',
+            ],
+            [
+                'value' => 29,
+                'name'  => '赠送',
+            ],
+            [
+                'value' => 30,
+                'name'  => '减贫解冻',
+            ],
+            [
+                'value' => 31,
+                'name'  => '平台赠送',
+            ],
+            [
+                'value' => 32,
+                '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       = '51';                                                              // 定义账号前缀,如银行标识
+        $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 '';
+        }
+
+    }
+
+/**
+ * 身份证校验
+ * @param $id
+ * @return bool
+ */
+function isValidChineseIDCard18($id) {
+    if (!preg_match('/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(10|11|12))((0[1-9])|([1-2][0-9])|30|31)\d{3}[\dXx]$/i', $id)) {
+        return false; // 格式不正确
+    }
+    // 校验码计算
+    $id = str_split($id);
+    $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
+    $checksum = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
+    $sum = 0;
+    foreach ($factor as $key => $value) {
+        $sum += $id[$key] * $value;
+    }
+    $mod = $sum % 11;
+    return strtoupper($id[17]) === $checksum[$mod]; // 比较校验码
+}

+ 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;
+}

+ 419 - 0
app/route.php

@@ -0,0 +1,419 @@
+<?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::any('/boost.html', [controller\LoginController::class, 'boost'])->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('/goods', function () {
+            /** -----项目 */
+            Route::any('/charity.html', [controller\GoodsController::class, 'charity'])->middleware([
+                \app\middleware\Sign::class,
+                \app\middleware\Decrypt::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('/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('/edid_address.html', [controller\GoodsController::class, 'edid_address'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::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('/card_transaction.html', [controller\BankCardController::class, 'card_transaction'])->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::any('/transfer.html', [controller\WithdrawController::class, 'transfer'])->middleware([
+                \app\middleware\Sign::class,
+                \app\middleware\UserToken::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::any('/user_raffle.html', [controller\RaffleController::class, 'userRaffle'])->middleware([
+                \app\middleware\Sign::class,
+                \app\middleware\UserToken::class,
+                \app\middleware\Decrypt::class
+            ]);
+            /** ----修改地址*/
+            Route::any('/save_raffle.html', [controller\RaffleController::class, 'save_raffle'])->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_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('/license', function () {
+//            /** 选择归属地,选择车牌 */
+//            Route::any('/optionexid.html', [controller\LicensePlateController::class, 'optionexid'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** 省列表 */
+//            Route::any('/provincelist.html', [controller\LicensePlateController::class, 'provincelist'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//            /** 车牌列表 */
+//            Route::any('/abbreviation.html', [controller\LicensePlateController::class, 'abbreviation'])->middleware([
+//                \app\middleware\Sign::class,
+//                \app\middleware\UserToken::class,
+//                \app\middleware\Decrypt::class
+//            ]);
+//        });
+
+//        Route::group('/applyrecord', function () {
+//            /** -----补偿申请*/
+//            Route::any('/applyrecord_add.html', [controller\ApplyrecordController::class, 'applyrecordAdd'])->middleware([
+//                //\app\middleware\Sign::class,
+//                \app\middleware\UserToken::class
+//            ]);
+//            /** -----补偿申请-详情*/
+//            Route::any('/applyrecord_details.html', [controller\ApplyrecordController::class, 'applyrecordDetails'])->middleware([
+//                //\app\middleware\Sign::class,
+//                \app\middleware\UserToken::class
+//            ]);
+//        });
+
+
+
+        /** 会员 */
+        Route::group('/user', function () {
+            /** 退出登录 */
+            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('/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::any('/cfxstat.html', [controller\UserController::class, 'cfxstat'])->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_four.html', [controller\PayController::class, 'paymentCallbackFour']);
+            Route::any('/payment_callback_five.html', [controller\PayController::class, 'paymentCallbackFive']);
+        });
+
+        /** 下发回调 */
+        Route::any('/issue.html', [controller\IssueController::class, 'index']);
+
+        Route::any('/issue_two.html', [controller\IssueController::class, 'indextwo']);
+
+        Route::any('/issue_three.html', [controller\IssueController::class, 'issue_three']);
+
+    });

+ 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.2.24",
+    "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,
+];

+ 164 - 0
config/log.php

@@ -0,0 +1,164 @@
+<?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],
+                ],
+            ]
+        ],
+    ], 'kaicard'      => [
+        'handlers' => [
+            [
+                'class'       => Monolog\Handler\RotatingFileHandler::class,
+                'constructor' => [
+                    runtime_path() . '/logs/kaicard.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
+];

+ 61 - 0
config/process.php

@@ -0,0 +1,61 @@
+<?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
+    ],
+    /**基金分红*/
+    'signTask'  => [
+        'handler'  => process\SignTask::class
+    ],
+//    /** 每天自动分红 */
+//    'taskFj'  => [
+//        'handler'  => process\TaskFj::class
+//    ],
+    /**矿机产生*/
+    '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:6001',
+    '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
+];

+ 25 - 0
env.txt

@@ -0,0 +1,25 @@
+#项目名称
+PROJECT='tt-05'
+PROJECTWEB='sjyh'
+#数据库
+DB_HOST='127.0.0.1'
+DB_PORT='13306'
+DB_DATABASE='tt-05sjyh'
+DB_USERNAME ='tt-05sjyh'
+DB_PASSWORD='tt-05sjyh'
+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='po3ksijh1864shi1'
+JWT_PRIVATEKEY='zgshisjs9huu832hb23e32432bsdbfh23423sdasdnuiwj4n4j'
+
+IMG='https://tt05sjyhapi.hingone.bond'
+
+API_HOST='https://tt05sjyhapi.hingone.bond'
+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',1)->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']);
+    }
+
+}

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


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