Pārlūkot izejas kodu

Add 人工支付 & 订单修改功能

- 添加 人工支付;
  - 添加微信、支付宝上传/显示;
  - 添加购买后TG机器人通知且快捷确认窗口;
- 添加订单可修改功能;
- 针对本次更新的初版页面添加与调整;
兔姬桑 4 gadi atpakaļ
vecāks
revīzija
4e06253359
43 mainītis faili ar 743 papildinājumiem un 345 dzēšanām
  1. 1 0
      .gitignore
  2. 0 4
      app/Components/Helpers.php
  3. 0 2
      app/Components/NetworkDetection.php
  4. 13 0
      app/Http/Controllers/Admin/LogsController.php
  5. 52 22
      app/Http/Controllers/Admin/SystemController.php
  6. 0 1
      app/Http/Controllers/Admin/ToolsController.php
  7. 0 1
      app/Http/Controllers/AuthController.php
  8. 0 2
      app/Http/Controllers/Gateway/AbstractPayment.php
  9. 66 0
      app/Http/Controllers/Gateway/Manual.php
  10. 2 2
      app/Http/Controllers/Gateway/Stripe.php
  11. 6 5
      app/Http/Controllers/PaymentController.php
  12. 0 1
      app/Http/Middleware/Affiliate.php
  13. 0 1
      app/Http/Middleware/SetLocale.php
  14. 1 2
      app/Http/Middleware/Telegram.php
  15. 1 2
      app/Http/Middleware/WebApi.php
  16. 0 1
      app/Http/Middleware/isForbidden.php
  17. 0 1
      app/Http/Middleware/isLogin.php
  18. 0 1
      app/Http/Middleware/isMaintenance.php
  19. 1 2
      app/Http/Middleware/isSecurity.php
  20. 1 0
      app/Models/Order.php
  21. 47 0
      app/Notifications/PaymentConfirm.php
  22. 8 1
      app/Observers/OrderObserver.php
  23. 137 136
      composer.lock
  24. 2 0
      config/common.php
  25. BIN
      public/assets/images/help/manual_wechat1.png
  26. BIN
      public/assets/images/help/manual_wechat2.png
  27. 0 0
      public/assets/images/payment/pay.svg
  28. 1 0
      resources/lang/en/common.php
  29. 1 1
      resources/lang/en/user.php
  30. 1 0
      resources/lang/zh_CN/common.php
  31. 1 1
      resources/lang/zh_CN/user.php
  32. 27 0
      resources/views/admin/config/system.blade.php
  33. 44 12
      resources/views/admin/logs/order.blade.php
  34. 41 43
      resources/views/admin/node/index.blade.php
  35. 39 41
      resources/views/admin/user/index.blade.php
  36. 0 0
      resources/views/user/components/payment/default.blade.php
  37. 212 0
      resources/views/user/components/payment/manual.blade.php
  38. 19 0
      resources/views/user/components/payment/stripe.blade.php
  39. 5 0
      resources/views/user/components/purchase.blade.php
  40. 7 41
      resources/views/user/services.blade.php
  41. 0 18
      resources/views/user/stripe-checkout.blade.php
  42. 1 0
      routes/admin.php
  43. 6 1
      routes/user.php

+ 1 - 0
.gitignore

@@ -25,3 +25,4 @@ _ide_helper.php
 .php_cs.cache
 node_modules/*
 composer.phar
+public/uploads/*

+ 0 - 4
app/Components/Helpers.php

@@ -153,7 +153,6 @@ class Helpers
      * @param  string  $address  收信方
      * @param  int  $status  投递状态
      * @param  string  $error  投递失败时记录的异常信息
-     *
      * @return int
      */
     public static function addNotificationLog(string $title, string $content, int $type, string $address = 'admin', int $status = 1, string $error = ''): int
@@ -177,7 +176,6 @@ class Helpers
      * @param  int  $couponId  优惠券ID
      * @param  int|null  $goodsId  商品ID
      * @param  int|null  $orderId  订单ID
-     *
      * @return bool
      */
     public static function addCouponLog($description, $couponId, $goodsId = null, $orderId = null): bool
@@ -200,7 +198,6 @@ class Helpers
      * @param  int  $after  记录后余额
      * @param  int  $amount  发生金额
      * @param  string  $description  描述
-     *
      * @return bool
      */
     public static function addUserCreditLog($userId, $orderId, $before, $after, $amount, $description = ''): bool
@@ -225,7 +222,6 @@ class Helpers
      * @param  int  $before  记录前的值
      * @param  int  $after  记录后的值
      * @param  string  $description  描述
-     *
      * @return bool
      */
     public static function addUserTrafficModifyLog($userId, $orderId, $before, $after, $description = ''): bool

+ 0 - 2
app/Components/NetworkDetection.php

@@ -11,7 +11,6 @@ class NetworkDetection
      * 用外部API进行Ping检测.
      *
      * @param  string  $ip  被检测的IP或者域名
-     *
      * @return bool
      */
     public function ping(string $ip)
@@ -66,7 +65,6 @@ class NetworkDetection
      * @param  string  $ip  被检测的IP
      * @param  bool  $is_icmp  TRUE 为ICMP,FALSE 为tcp
      * @param  int|null  $port  检测端口,默认为空
-     *
      * @return bool
      */
     public function networkCheck(string $ip, bool $is_icmp, int $port = null)

+ 13 - 0
app/Http/Controllers/Admin/LogsController.php

@@ -15,6 +15,7 @@ use App\Models\UserCreditLog;
 use App\Models\UserDataFlowLog;
 use App\Models\UserDataModifyLog;
 use Illuminate\Http\Request;
+use Response;
 
 class LogsController extends Controller
 {
@@ -58,6 +59,18 @@ class LogsController extends Controller
         return view('admin.logs.order', ['orders' => $query->sortable(['id' => 'desc'])->paginate(15)->appends($request->except('page'))]);
     }
 
+    public function changeOrderStatus(Request $request)
+    {
+        $order = Order::findOrFail($request->input('oid'));
+        $status = $request->input('status');
+
+        if ($order->update(['status' => $status])) {
+            return Response::json(['status' => 'success', 'message' => '更新成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '更新失败']);
+    }
+
     // 流量日志
     public function trafficLog(Request $request)
     {

+ 52 - 22
app/Http/Controllers/Admin/SystemController.php

@@ -66,36 +66,66 @@ class SystemController extends Controller
         return sysConfig('captcha_secret') && sysConfig('captcha_key');
     }
 
-    public function setExtend(Request $request): RedirectResponse  // 设置系统扩展信息,例如客服、统计代码
+    public function setExtend(Request $request): RedirectResponse  // 设置涉及到上传的设置
     {
-        if ($request->hasFile('website_home_logo')) {
-            $validator = validator()->make($request->all(), ['website_home_logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
-
-            if ($validator->fails()) {
-                return redirect()->route('admin.system.index', '#other')->withErrors($validator->errors());
+        if ($request->hasAny(['website_home_logo', 'website_home_logo'])) { // 首页LOGO
+            if ($request->hasFile('website_home_logo')) {
+                $validator = validator()->make($request->all(), ['website_home_logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
+
+                if ($validator->fails()) {
+                    return redirect()->route('admin.system.index', '#other')->withErrors($validator->errors());
+                }
+                $file = $request->file('website_home_logo');
+                $ret = $file->move('uploads/logo', $file->getClientOriginalName());
+                if ($ret && Config::find('website_home_logo')->update(['value' => 'uploads/logo/'.$file->getClientOriginalName()])) {
+                    return redirect()->route('admin.system.index', '#other')->with('successMsg', '更新成功');
+                }
             }
-            $file = $request->file('website_home_logo');
-            $ret = $file->move('uploads/logo', $file->getClientOriginalName());
-            if ($ret && Config::find('website_home_logo')->update(['value' => 'uploads/logo/'.$file->getClientOriginalName()])) {
-                return redirect()->route('admin.system.index', '#other')->with('successMsg', '更新成功');
+            if ($request->hasFile('website_logo')) { // 站内LOGO
+                $validator = validator()->make($request->all(), ['website_logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
+
+                if ($validator->fails()) {
+                    return redirect()->route('admin.system.index', '#other')->withErrors($validator->errors());
+                }
+                $file = $request->file('website_logo');
+                $ret = $file->move('uploads/logo', $file->getClientOriginalName());
+                if ($ret && Config::findOrFail('website_logo')->update(['value' => 'uploads/logo/'.$file->getClientOriginalName()])) {
+                    return redirect()->route('admin.system.index', '#other')->with('successMsg', '更新成功');
+                }
             }
-        }
-
-        // 站内LOGO
-        if ($request->hasFile('website_logo')) {
-            $validator = validator()->make($request->all(), ['website_logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
 
-            if ($validator->fails()) {
-                return redirect()->route('admin.system.index', '#other')->withErrors($validator->errors());
+            return redirect()->route('admin.system.index', '#other')->withErrors('更新失败');
+        } elseif ($request->hasAny(['alipay_qrcode', 'wechat_qrcode'])) {
+            if ($request->hasFile('alipay_qrcode')) {
+                $validator = validator()->make($request->all(), ['alipay_qrcode' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
+
+                if ($validator->fails()) {
+                    return redirect()->route('admin.system.index', '#payment')->withErrors($validator->errors());
+                }
+                $file = $request->file('alipay_qrcode');
+                $ret = $file->move('uploads/images', $file->getClientOriginalName());
+                if ($ret && Config::find('alipay_qrcode')->update(['value' => 'uploads/images/'.$file->getClientOriginalName()])) {
+                    return redirect()->route('admin.system.index', '#payment')->with('successMsg', '更新成功');
+                }
             }
-            $file = $request->file('website_logo');
-            $ret = $file->move('uploads/logo', $file->getClientOriginalName());
-            if ($ret && Config::findOrFail('website_logo')->update(['value' => 'uploads/logo/'.$file->getClientOriginalName()])) {
-                return redirect()->route('admin.system.index', '#other')->with('successMsg', '更新成功');
+
+            if ($request->hasFile('wechat_qrcode')) { // 站内LOGO
+                $validator = validator()->make($request->all(), ['wechat_qrcode' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048']);
+
+                if ($validator->fails()) {
+                    return redirect()->route('admin.system.index', '#payment')->withErrors($validator->errors());
+                }
+                $file = $request->file('wechat_qrcode');
+                $ret = $file->move('uploads/images', $file->getClientOriginalName());
+                if ($ret && Config::findOrFail('wechat_qrcode')->update(['value' => 'uploads/images/'.$file->getClientOriginalName()])) {
+                    return redirect()->route('admin.system.index', '#payment')->with('successMsg', '更新成功');
+                }
             }
+
+            return redirect()->route('admin.system.index', '#payment')->withErrors('更新失败');
         }
 
-        return redirect()->route('admin.system.index', '#other')->withErrors('更新失败');
+        return redirect()->route('admin.system.index');
     }
 
     public function setConfig(SystemRequest $request): JsonResponse // 设置某个配置项

+ 0 - 1
app/Http/Controllers/Admin/ToolsController.php

@@ -254,7 +254,6 @@ class ToolsController extends Controller
      * 计算文件行数.
      *
      * @param $file
-     *
      * @return int
      */
     private function countLine($file): int

+ 0 - 1
app/Http/Controllers/AuthController.php

@@ -338,7 +338,6 @@ class AuthController extends Controller
      *
      * @param  string|null  $code  邀请码
      * @param  int|null  $aff  URL中的aff参数
-     *
      * @return array
      */
     private function getAff($code = null, $aff = null): array

+ 0 - 2
app/Http/Controllers/Gateway/AbstractPayment.php

@@ -31,7 +31,6 @@ abstract class AbstractPayment
      * @param  string  $trade_no  本地订单号
      * @param  string  $out_trade_no  外部订单号
      * @param  int  $amount  交易金额
-     *
      * @return int
      */
     protected function addPamentCallback(string $trade_no, string $out_trade_no, int $amount): int
@@ -56,7 +55,6 @@ abstract class AbstractPayment
      * @param  array  $data  需要加密的数组
      * @param  string  $key  尾部的密钥
      * @param  bool  $filter  是否清理空值
-     *
      * @return string md5加密后的数据
      */
     protected function aliStyleSign(array $data, string $key, bool $filter = true): string

+ 66 - 0
app/Http/Controllers/Gateway/Manual.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use App\Models\Payment;
+use Auth;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Response;
+
+class Manual extends AbstractPayment
+{
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        if ($payment) {
+            $url = route('manual.checkout', ['payment' => $payment->trade_no]);
+            $payment->update(['url' => $url]);
+
+            return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '购买失败,请尝试其他方式']);
+    }
+
+    public function redirectPage($trade_no)
+    {
+        $payment = Payment::uid()->with(['order', 'order.goods'])->whereTradeNo($trade_no)->firstOrFail();
+        $goods = $payment->order->goods;
+
+        return view('user.components.payment.manual', [
+            'payment'       => $payment,
+            'name'          => $goods->name ?? trans('user.recharge_credit'),
+            'days'          => $goods->days ?? 0,
+            'pay_type'      => $payment->order->pay_type_label ?: 0,
+            'pay_type_icon' => $payment->order->pay_type_icon,
+        ]);
+    }
+
+    public function inform($trade_no)
+    {
+        $payment = Payment::uid()->with(['order'])->whereTradeNo($trade_no)->firstOrFail();
+        $payment->order->update(['status' => 1]);
+
+        return Response::json(['status' => 'success', 'message' => '我们将在【24小时】内对购买/充值的款项进行开通!请耐心等待']);
+    }
+
+    public function notify(Request $request): void
+    {
+        $code = $request->input('sign');
+        $status = $request->input('status');
+        if ($code && $status) {
+            $id = openssl_decrypt(base64url_decode($code), 'aes-128-ctr', config('app.key'), OPENSSL_RAW_DATA);
+            $payment = Payment::findOrFail($id);
+            if ($payment && $payment->order) {
+                $payment->order->complete();
+            }
+        }
+    }
+
+    public function decode($string)
+    {
+        return openssl_decrypt(base64url_decode($string), 'aes-128-ctr', config('app.key'), OPENSSL_RAW_DATA);
+    }
+}

+ 2 - 2
app/Http/Controllers/Gateway/Stripe.php

@@ -29,7 +29,7 @@ class Stripe extends AbstractPayment
         try {
             $session = Session::create($data);
 
-            $url = route('stripe-checkout', ['session_id' => $session->id]);
+            $url = route('stripe.checkout', ['session_id' => $session->id]);
             $payment->update(['url' => $url]);
 
             return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
@@ -66,7 +66,7 @@ class Stripe extends AbstractPayment
     // redirect to Stripe Payment url
     public function redirectPage($session_id)
     {
-        return view('user.stripe-checkout', ['session_id' => $session_id]);
+        return view('user.components.payment.stripe', ['session_id' => $session_id]);
     }
 
     // url = '/callback/notify?method=stripe'

+ 6 - 5
app/Http/Controllers/PaymentController.php

@@ -8,6 +8,7 @@ use App\Http\Controllers\Gateway\CodePay;
 use App\Http\Controllers\Gateway\EPay;
 use App\Http\Controllers\Gateway\F2Fpay;
 use App\Http\Controllers\Gateway\Local;
+use App\Http\Controllers\Gateway\Manual;
 use App\Http\Controllers\Gateway\PayBeaver;
 use App\Http\Controllers\Gateway\PayJs;
 use App\Http\Controllers\Gateway\PayPal;
@@ -59,10 +60,11 @@ class PaymentController extends Controller
                 return new PayBeaver();
             case 'theadpay':
                 return new THeadPay();
+            case 'manual':
+                return new Manual();
             default:
                 Log::emergency('未知支付:'.self::$method);
-
-                return false;
+                exit();
         }
     }
 
@@ -100,8 +102,7 @@ class PaymentController extends Controller
                 return Response::json(['status' => 'fail', 'message' => trans('user.payment.error')]);
             }
             $amount = $credit;
-        // 购买服务
-        } elseif ($goods_id && self::$method) {
+        } elseif ($goods_id && self::$method) { // 购买服务
             $goods = Goods::find($goods_id);
             if (! $goods || ! $goods->status) {
                 return Response::json(['status' => 'fail', 'message' => '订单创建失败:商品已下架']);
@@ -209,7 +210,7 @@ class PaymentController extends Controller
         $payment = Payment::uid()->with(['order', 'order.goods'])->whereTradeNo($trade_no)->firstOrFail();
         $goods = $payment->order->goods;
 
-        return view('user.payment', [
+        return view('user.components.payment.default', [
             'payment'       => $payment,
             'name'          => $goods->name ?? trans('user.recharge_credit'),
             'days'          => $goods->days ?? 0,

+ 0 - 1
app/Http/Middleware/Affiliate.php

@@ -13,7 +13,6 @@ class Affiliate
      *
      * @param  Request  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle(Request $request, Closure $next)

+ 0 - 1
app/Http/Middleware/SetLocale.php

@@ -13,7 +13,6 @@ class SetLocale
      *
      * @param  Request  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle(Request $request, Closure $next)

+ 1 - 2
app/Http/Middleware/Telegram.php

@@ -9,9 +9,8 @@ class Telegram
     /**
      * Handle an incoming request.
      *
-     * @param           $request
+     * @param  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle($request, Closure $next)

+ 1 - 2
app/Http/Middleware/WebApi.php

@@ -11,9 +11,8 @@ class WebApi
     /**
      * Handle an incoming request.
      *
-     * @param           $request
+     * @param  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle($request, Closure $next)

+ 0 - 1
app/Http/Middleware/isForbidden.php

@@ -16,7 +16,6 @@ class isForbidden
      *
      * @param  Request  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle(Request $request, Closure $next)

+ 0 - 1
app/Http/Middleware/isLogin.php

@@ -13,7 +13,6 @@ class isLogin
      *
      * @param  Request  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle(Request $request, Closure $next)

+ 0 - 1
app/Http/Middleware/isMaintenance.php

@@ -12,7 +12,6 @@ class isMaintenance
      *
      * @param  Request  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle(Request $request, Closure $next)

+ 1 - 2
app/Http/Middleware/isSecurity.php

@@ -13,9 +13,8 @@ class isSecurity
     /**
      * 是否需要安全码才访问(仅用于登录页).
      *
-     * @param           $request
+     * @param  $request
      * @param  Closure  $next
-     *
      * @return mixed
      */
     public function handle($request, Closure $next)

+ 1 - 0
app/Models/Order.php

@@ -167,6 +167,7 @@ class Order extends Model
             4 => trans('common.payment.crypto'),
             5 => 'PayPal',
             6 => 'Stripe',
+            7 => trans('common.payment.manual'),
         ][$this->attributes['pay_type']] ?? '';
     }
 

+ 47 - 0
app/Notifications/PaymentConfirm.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Notifications;
+
+use App\Models\Order;
+use App\Models\User;
+use Illuminate\Bus\Queueable;
+use Illuminate\Notifications\Notification;
+use NotificationChannels\Telegram\TelegramChannel;
+use NotificationChannels\Telegram\TelegramMessage;
+
+class PaymentConfirm extends Notification
+{
+    use Queueable;
+
+    private $order;
+
+    public function __construct(Order $order)
+    {
+        $this->order = $order;
+    }
+
+    public function via($notifiable)
+    {
+        return [TelegramChannel::class];
+    }
+
+    public function toTelegram($notifiable)
+    {
+        $order = $this->order;
+        $goods = $this->order->goods;
+        $sign = base64url_encode(openssl_encrypt($order->payment->id, 'aes-128-ctr', config('app.key'), OPENSSL_RAW_DATA));
+        $message = sprintf("🛒 人工支付\n————————\n\t💰 金额:%s\n\t📦 商品:%s\n\t", $order->amount, $goods->name ?? '余额充值');
+        foreach (User::role('Super Admin')->get() as $admin) {
+            if (! $admin->telegram_user_id) {
+                continue;
+            }
+
+            return TelegramMessage::create()
+                ->to($admin->telegram_user_id)
+                ->token(sysConfig('telegram_token'))
+                ->content($message)
+                ->button('确 认', route('payment.notify', ['method' => 'manual', 'sign' => $sign, 'status' => 1]))
+                ->button('否 決', route('payment.notify', ['method' => 'manual', 'sign' => $sign, 'status' => 0]));
+        }
+    }
+}

+ 8 - 1
app/Observers/OrderObserver.php

@@ -5,8 +5,11 @@ namespace App\Observers;
 use App\Components\Helpers;
 use App\Models\Coupon;
 use App\Models\Order;
+use App\Models\User;
+use App\Notifications\PaymentConfirm;
 use App\Services\OrderService;
 use Arr;
+use Notification;
 
 class OrderObserver
 {
@@ -24,6 +27,10 @@ class OrderObserver
                 }
             }
 
+            if ($changes['status'] === 1) { // 待确认支付
+                Notification::send(User::find(1), new PaymentConfirm($order));
+            }
+
             // 本地订单-在线订单 支付成功互联
             if ($changes['status'] === 2 && $order->getOriginal('status') !== 3) {
                 (new OrderService($order))->receivedPayment();
@@ -39,7 +46,7 @@ class OrderObserver
             $prepaidOrder = Order::userPrepay($order->user_id)->oldest()->first();
 
             if ($prepaidOrder) {
-                (new OrderService($prepaidOrder))->activatePrepaidPlan();
+                (new OrderService($prepaidOrder))->activatePrepaidPlan(); // 激活预支付
             }
         }
     }

+ 137 - 136
composer.lock

@@ -2089,16 +2089,16 @@
         },
         {
             "name": "laravel-lang/lang",
-            "version": "10.1.3",
+            "version": "10.1.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Laravel-Lang/lang.git",
-                "reference": "68adbec33de30777cddbfd99cef1e3fb16237a5a"
+                "reference": "55866218d0d4ebefc4e7d82ecf7e85f6cbf1014d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/68adbec33de30777cddbfd99cef1e3fb16237a5a",
-                "reference": "68adbec33de30777cddbfd99cef1e3fb16237a5a",
+                "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/55866218d0d4ebefc4e7d82ecf7e85f6cbf1014d",
+                "reference": "55866218d0d4ebefc4e7d82ecf7e85f6cbf1014d",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -2150,7 +2150,7 @@
                 "issues": "https://github.com/Laravel-Lang/lang/issues",
                 "source": "https://github.com/Laravel-Lang/lang"
             },
-            "time": "2021-07-08T19:28:32+00:00"
+            "time": "2021-09-05T08:48:03+00:00"
         },
         {
             "name": "laravel-notification-channels/bearychat",
@@ -2448,16 +2448,16 @@
         },
         {
             "name": "laravel/socialite",
-            "version": "v5.2.4",
+            "version": "v5.2.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/socialite.git",
-                "reference": "59e2f8d9d9663029c7746a92d60bbb7697953bb9"
+                "reference": "fd0f6a3dd963ca480b598649b54f92d81a43617f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/socialite/zipball/59e2f8d9d9663029c7746a92d60bbb7697953bb9",
-                "reference": "59e2f8d9d9663029c7746a92d60bbb7697953bb9",
+                "url": "https://api.github.com/repos/laravel/socialite/zipball/fd0f6a3dd963ca480b598649b54f92d81a43617f",
+                "reference": "fd0f6a3dd963ca480b598649b54f92d81a43617f",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -2519,7 +2519,7 @@
                 "issues": "https://github.com/laravel/socialite/issues",
                 "source": "https://github.com/laravel/socialite"
             },
-            "time": "2021-08-10T17:44:52+00:00"
+            "time": "2021-08-31T15:16:26+00:00"
         },
         {
             "name": "laravel/tinker",
@@ -3883,16 +3883,16 @@
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.52.0",
+            "version": "2.53.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe"
+                "reference": "f4655858a784988f880c1b8c7feabbf02dfdf045"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/369c0e2737c56a0f39c946dd261855255a6fccbe",
-                "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f4655858a784988f880c1b8c7feabbf02dfdf045",
+                "reference": "f4655858a784988f880c1b8c7feabbf02dfdf045",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -3910,7 +3910,7 @@
             },
             "require-dev": {
                 "doctrine/orm": "^2.7",
-                "friendsofphp/php-cs-fixer": "^2.14 || ^3.0",
+                "friendsofphp/php-cs-fixer": "^3.0",
                 "kylekatarnls/multi-tester": "^2.0",
                 "phpmd/phpmd": "^2.9",
                 "phpstan/extension-installer": "^1.0",
@@ -3979,7 +3979,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-08-14T19:10:52+00:00"
+            "time": "2021-09-06T09:29:23+00:00"
         },
         {
             "name": "nikic/php-parser",
@@ -4297,16 +4297,16 @@
         },
         {
             "name": "phpoption/phpoption",
-            "version": "1.7.5",
+            "version": "1.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/schmittjoh/php-option.git",
-                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525"
+                "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525",
-                "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525",
+                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5455cb38aed4523f99977c4a12ef19da4bfe2a28",
+                "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -4316,16 +4316,16 @@
                 ]
             },
             "require": {
-                "php": "^5.5.9 || ^7.0 || ^8.0"
+                "php": "^7.0 || ^8.0"
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.4.1",
-                "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0"
+                "phpunit/phpunit": "^6.5.14 || ^7.0.20 || ^8.5.19 || ^9.5.8"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.7-dev"
+                    "dev-master": "1.8-dev"
                 }
             },
             "autoload": {
@@ -4344,7 +4344,7 @@
                 },
                 {
                     "name": "Graham Campbell",
-                    "email": "[email protected]"
+                    "email": "[email protected]"
                 }
             ],
             "description": "Option Type for PHP",
@@ -4356,7 +4356,7 @@
             ],
             "support": {
                 "issues": "https://github.com/schmittjoh/php-option/issues",
-                "source": "https://github.com/schmittjoh/php-option/tree/1.7.5"
+                "source": "https://github.com/schmittjoh/php-option/tree/1.8.0"
             },
             "funding": [
                 {
@@ -4368,7 +4368,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-07-20T17:29:33+00:00"
+            "time": "2021-08-28T21:27:29+00:00"
         },
         {
             "name": "psr/container",
@@ -5354,16 +5354,16 @@
         },
         {
             "name": "spatie/laravel-permission",
-            "version": "4.3.0",
+            "version": "4.4.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/laravel-permission.git",
-                "reference": "78eaa5e06c313a9f3672a7571b4d83b913721b72"
+                "reference": "3c9d7ae7683081ee90a4e2297f4e58aff3492a1e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/78eaa5e06c313a9f3672a7571b4d83b913721b72",
-                "reference": "78eaa5e06c313a9f3672a7571b4d83b913721b72",
+                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/3c9d7ae7683081ee90a4e2297f4e58aff3492a1e",
+                "reference": "3c9d7ae7683081ee90a4e2297f4e58aff3492a1e",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5426,7 +5426,7 @@
             ],
             "support": {
                 "issues": "https://github.com/spatie/laravel-permission/issues",
-                "source": "https://github.com/spatie/laravel-permission/tree/4.3.0"
+                "source": "https://github.com/spatie/laravel-permission/tree/4.4.1"
             },
             "funding": [
                 {
@@ -5434,7 +5434,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-08-17T18:37:17+00:00"
+            "time": "2021-09-01T17:40:58+00:00"
         },
         {
             "name": "srmklive/paypal",
@@ -5503,16 +5503,16 @@
         },
         {
             "name": "stripe/stripe-php",
-            "version": "v7.94.0",
+            "version": "v7.95.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/stripe/stripe-php.git",
-                "reference": "03cd6b5c1c4fc9087ddd1dd046457bff274294d6"
+                "reference": "ed372a1f6430b06dda408bb33b27d2be35ceaf07"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/03cd6b5c1c4fc9087ddd1dd046457bff274294d6",
-                "reference": "03cd6b5c1c4fc9087ddd1dd046457bff274294d6",
+                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/ed372a1f6430b06dda408bb33b27d2be35ceaf07",
+                "reference": "ed372a1f6430b06dda408bb33b27d2be35ceaf07",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5564,9 +5564,9 @@
             ],
             "support": {
                 "issues": "https://github.com/stripe/stripe-php/issues",
-                "source": "https://github.com/stripe/stripe-php/tree/v7.94.0"
+                "source": "https://github.com/stripe/stripe-php/tree/v7.95.0"
             },
-            "time": "2021-08-19T14:15:27+00:00"
+            "time": "2021-09-02T02:30:40+00:00"
         },
         {
             "name": "swiftmailer/swiftmailer",
@@ -5651,16 +5651,16 @@
         },
         {
             "name": "symfony/console",
-            "version": "v5.3.6",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2"
+                "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
-                "reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
+                "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a",
+                "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5736,7 +5736,7 @@
                 "terminal"
             ],
             "support": {
-                "source": "https://github.com/symfony/console/tree/v5.3.6"
+                "source": "https://github.com/symfony/console/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -5752,7 +5752,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-27T19:10:22+00:00"
+            "time": "2021-08-25T20:02:16+00:00"
         },
         {
             "name": "symfony/css-selector",
@@ -5901,16 +5901,16 @@
         },
         {
             "name": "symfony/error-handler",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/error-handler.git",
-                "reference": "281f6c4660bcf5844bb0346fe3a4664722fe4c73"
+                "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/error-handler/zipball/281f6c4660bcf5844bb0346fe3a4664722fe4c73",
-                "reference": "281f6c4660bcf5844bb0346fe3a4664722fe4c73",
+                "url": "https://api.github.com/repos/symfony/error-handler/zipball/3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321",
+                "reference": "3bc60d0fba00ae8d1eaa9eb5ab11a2bbdd1fc321",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5955,7 +5955,7 @@
             "description": "Provides tools to manage errors and ease debugging PHP code",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/error-handler/tree/v5.3.4"
+                "source": "https://github.com/symfony/error-handler/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -5971,20 +5971,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-23T15:55:36+00:00"
+            "time": "2021-08-28T15:07:08+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "f2fd2208157553874560f3645d4594303058c4bd"
+                "reference": "ce7b20d69c66a20939d8952b617506a44d102130"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f2fd2208157553874560f3645d4594303058c4bd",
-                "reference": "f2fd2208157553874560f3645d4594303058c4bd",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ce7b20d69c66a20939d8952b617506a44d102130",
+                "reference": "ce7b20d69c66a20939d8952b617506a44d102130",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6046,7 +6046,7 @@
             "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.4"
+                "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -6062,7 +6062,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-23T15:55:36+00:00"
+            "time": "2021-08-04T21:20:46+00:00"
         },
         {
             "name": "symfony/event-dispatcher-contracts",
@@ -6151,16 +6151,16 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "17f50e06018baec41551a71a15731287dbaab186"
+                "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/17f50e06018baec41551a71a15731287dbaab186",
-                "reference": "17f50e06018baec41551a71a15731287dbaab186",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93",
+                "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6199,7 +6199,7 @@
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/finder/tree/v5.3.4"
+                "source": "https://github.com/symfony/finder/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -6215,7 +6215,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-23T15:54:19+00:00"
+            "time": "2021-08-04T21:20:46+00:00"
         },
         {
             "name": "symfony/http-client-contracts",
@@ -6303,16 +6303,16 @@
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v5.3.6",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75"
+                "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a8388f7b7054a7401997008ce9cd8c6b0ab7ac75",
-                "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5",
+                "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6362,7 +6362,7 @@
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v5.3.6"
+                "source": "https://github.com/symfony/http-foundation/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -6378,20 +6378,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-27T17:08:17+00:00"
+            "time": "2021-08-27T11:20:35+00:00"
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v5.3.6",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "60030f209018356b3b553b9dbd84ad2071c1b7e0"
+                "reference": "a3a78e37935a527b50376c22ac1cec35b57fe787"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/60030f209018356b3b553b9dbd84ad2071c1b7e0",
-                "reference": "60030f209018356b3b553b9dbd84ad2071c1b7e0",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a3a78e37935a527b50376c22ac1cec35b57fe787",
+                "reference": "a3a78e37935a527b50376c22ac1cec35b57fe787",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6407,7 +6407,7 @@
                 "symfony/error-handler": "^4.4|^5.0",
                 "symfony/event-dispatcher": "^5.0",
                 "symfony/http-client-contracts": "^1.1|^2",
-                "symfony/http-foundation": "^5.3",
+                "symfony/http-foundation": "^5.3.7",
                 "symfony/polyfill-ctype": "^1.8",
                 "symfony/polyfill-php73": "^1.9",
                 "symfony/polyfill-php80": "^1.16"
@@ -6480,7 +6480,7 @@
             "description": "Provides a structured process for converting a Request into a Response",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-kernel/tree/v5.3.6"
+                "source": "https://github.com/symfony/http-kernel/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -6496,20 +6496,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-29T07:06:27+00:00"
+            "time": "2021-08-30T12:37:19+00:00"
         },
         {
             "name": "symfony/mime",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mime.git",
-                "reference": "633e4e8afe9e529e5599d71238849a4218dd497b"
+                "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/mime/zipball/633e4e8afe9e529e5599d71238849a4218dd497b",
-                "reference": "633e4e8afe9e529e5599d71238849a4218dd497b",
+                "url": "https://api.github.com/repos/symfony/mime/zipball/ae887cb3b044658676129f5e97aeb7e9eb69c2d8",
+                "reference": "ae887cb3b044658676129f5e97aeb7e9eb69c2d8",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6569,7 +6569,7 @@
                 "mime-type"
             ],
             "support": {
-                "source": "https://github.com/symfony/mime/tree/v5.3.4"
+                "source": "https://github.com/symfony/mime/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -6585,7 +6585,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-21T12:40:44+00:00"
+            "time": "2021-08-20T11:40:01+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
@@ -7531,16 +7531,16 @@
         },
         {
             "name": "symfony/process",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "d16634ee55b895bd85ec714dadc58e4428ecf030"
+                "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/d16634ee55b895bd85ec714dadc58e4428ecf030",
-                "reference": "d16634ee55b895bd85ec714dadc58e4428ecf030",
+                "url": "https://api.github.com/repos/symfony/process/zipball/38f26c7d6ed535217ea393e05634cb0b244a1967",
+                "reference": "38f26c7d6ed535217ea393e05634cb0b244a1967",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -7579,7 +7579,7 @@
             "description": "Executes commands in sub-processes",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/process/tree/v5.3.4"
+                "source": "https://github.com/symfony/process/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -7595,20 +7595,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-23T15:54:19+00:00"
+            "time": "2021-08-04T21:20:46+00:00"
         },
         {
             "name": "symfony/routing",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "0a35d2f57d73c46ab6d042ced783b81d09a624c4"
+                "reference": "be865017746fe869007d94220ad3f5297951811b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/0a35d2f57d73c46ab6d042ced783b81d09a624c4",
-                "reference": "0a35d2f57d73c46ab6d042ced783b81d09a624c4",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/be865017746fe869007d94220ad3f5297951811b",
+                "reference": "be865017746fe869007d94220ad3f5297951811b",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -7675,7 +7675,7 @@
                 "url"
             ],
             "support": {
-                "source": "https://github.com/symfony/routing/tree/v5.3.4"
+                "source": "https://github.com/symfony/routing/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -7691,7 +7691,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-23T15:55:36+00:00"
+            "time": "2021-08-04T21:42:42+00:00"
         },
         {
             "name": "symfony/service-contracts",
@@ -7780,16 +7780,16 @@
         },
         {
             "name": "symfony/string",
-            "version": "v5.3.3",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
-                "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1"
+                "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
-                "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1",
+                "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5",
+                "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -7849,7 +7849,7 @@
                 "utf8"
             ],
             "support": {
-                "source": "https://github.com/symfony/string/tree/v5.3.3"
+                "source": "https://github.com/symfony/string/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -7865,20 +7865,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-06-27T11:44:38+00:00"
+            "time": "2021-08-26T08:00:08+00:00"
         },
         {
             "name": "symfony/translation",
-            "version": "v5.3.4",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
-                "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1"
+                "reference": "4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
-                "reference": "d89ad7292932c2699cbe4af98d72c5c6bbc504c1",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6",
+                "reference": "4d595a6d15fd3a2c67f6f31d14d15d3b7356d7a6",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -7950,7 +7950,7 @@
             "description": "Provides tools to internationalize your application",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/translation/tree/v5.3.4"
+                "source": "https://github.com/symfony/translation/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -7966,7 +7966,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-25T09:39:16+00:00"
+            "time": "2021-08-26T08:22:53+00:00"
         },
         {
             "name": "symfony/translation-contracts",
@@ -8054,16 +8054,16 @@
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v5.3.6",
+            "version": "v5.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0"
+                "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
-                "reference": "3dd8ddd1e260e58ecc61bb78da3b6584b3bfcba0",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f",
+                "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -8128,7 +8128,7 @@
                 "dump"
             ],
             "support": {
-                "source": "https://github.com/symfony/var-dumper/tree/v5.3.6"
+                "source": "https://github.com/symfony/var-dumper/tree/v5.3.7"
             },
             "funding": [
                 {
@@ -8144,7 +8144,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-27T01:56:02+00:00"
+            "time": "2021-08-04T23:19:25+00:00"
         },
         {
             "name": "symfony/yaml",
@@ -9847,16 +9847,16 @@
         },
         {
             "name": "facade/ignition",
-            "version": "2.11.4",
+            "version": "2.12.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/facade/ignition.git",
-                "reference": "1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2"
+                "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/facade/ignition/zipball/1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2",
-                "reference": "1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2",
+                "url": "https://api.github.com/repos/facade/ignition/zipball/74dcc32a2895a126d1e5f2cd3bbab499cac66db1",
+                "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -9925,7 +9925,7 @@
                 "issues": "https://github.com/facade/ignition/issues",
                 "source": "https://github.com/facade/ignition"
             },
-            "time": "2021-08-17T11:45:33+00:00"
+            "time": "2021-08-24T09:53:54+00:00"
         },
         {
             "name": "facade/ignition-contracts",
@@ -9988,16 +9988,16 @@
         },
         {
             "name": "fakerphp/faker",
-            "version": "v1.15.0",
+            "version": "v1.16.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FakerPHP/Faker.git",
-                "reference": "89c6201c74db25fa759ff16e78a4d8f32547770e"
+                "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/89c6201c74db25fa759ff16e78a4d8f32547770e",
-                "reference": "89c6201c74db25fa759ff16e78a4d8f32547770e",
+                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/271d384d216e5e5c468a6b28feedf95d49f83b35",
+                "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -10008,7 +10008,7 @@
             },
             "require": {
                 "php": "^7.1 || ^8.0",
-                "psr/container": "^1.0",
+                "psr/container": "^1.0 || ^2.0",
                 "symfony/deprecation-contracts": "^2.2"
             },
             "conflict": {
@@ -10028,7 +10028,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "v1.15-dev"
+                    "dev-main": "v1.16-dev"
                 }
             },
             "autoload": {
@@ -10053,22 +10053,22 @@
             ],
             "support": {
                 "issues": "https://github.com/FakerPHP/Faker/issues",
-                "source": "https://github.com/FakerPHP/Faker/tree/v1.15.0"
+                "source": "https://github.com/FakerPHP/Faker/tree/v1.16.0"
             },
-            "time": "2021-07-06T20:39:40+00:00"
+            "time": "2021-09-06T14:53:37+00:00"
         },
         {
             "name": "filp/whoops",
-            "version": "2.14.0",
+            "version": "2.14.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/filp/whoops.git",
-                "reference": "fdf92f03e150ed84d5967a833ae93abffac0315b"
+                "reference": "15ead64e9828f0fc90932114429c4f7923570cb1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/filp/whoops/zipball/fdf92f03e150ed84d5967a833ae93abffac0315b",
-                "reference": "fdf92f03e150ed84d5967a833ae93abffac0315b",
+                "url": "https://api.github.com/repos/filp/whoops/zipball/15ead64e9828f0fc90932114429c4f7923570cb1",
+                "reference": "15ead64e9828f0fc90932114429c4f7923570cb1",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -10124,7 +10124,7 @@
             ],
             "support": {
                 "issues": "https://github.com/filp/whoops/issues",
-                "source": "https://github.com/filp/whoops/tree/2.14.0"
+                "source": "https://github.com/filp/whoops/tree/2.14.1"
             },
             "funding": [
                 {
@@ -10132,7 +10132,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-07-13T12:00:00+00:00"
+            "time": "2021-08-29T12:00:00+00:00"
         },
         {
             "name": "hamcrest/hamcrest-php",
@@ -11744,16 +11744,16 @@
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.5.8",
+            "version": "9.5.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb"
+                "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/191768ccd5c85513b4068bdbe99bb6390c7d54fb",
-                "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b",
+                "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -11837,7 +11837,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.8"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9"
             },
             "funding": [
                 {
@@ -11849,7 +11849,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-07-31T15:17:34+00:00"
+            "time": "2021-08-31T06:47:40+00:00"
         },
         {
             "name": "react/promise",
@@ -12844,6 +12844,7 @@
                     "type": "github"
                 }
             ],
+            "abandoned": true,
             "time": "2020-09-28T06:45:17+00:00"
         },
         {

+ 2 - 0
config/common.php

@@ -8,6 +8,7 @@ return [
             'credit'    => '余额',
             'epay'      => '易支付',
             'f2fpay'    => '支付宝当面付',
+            'manual'    => '人工支付',
             'paybeaver' => '海狸支付',
             'payjs'     => 'PayJs',
             'paypal'    => 'PayPal',
@@ -23,6 +24,7 @@ return [
             4 => 'coin.png',
             5 => 'paypal.png',
             6 => 'stripe.png',
+            7 => 'pay.svg',
         ],
     ],
 

BIN
public/assets/images/help/manual_wechat1.png


BIN
public/assets/images/help/manual_wechat2.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
public/assets/images/payment/pay.svg


+ 1 - 0
resources/lang/en/common.php

@@ -77,6 +77,7 @@ return [
         'wechat' => 'Wechat',
         'alipay' => 'Alipay',
         'crypto' => 'Cryptocurrency',
+        'manual' => 'Manual Pay',
     ],
     'recommend'      => 'Recommend',
     'advance'        => 'Advance',

+ 1 - 1
resources/lang/en/user.php

@@ -170,7 +170,7 @@ return [
     'payment'             => [
         'error'           => 'The recharge balance is not compliant',
         'creating'        => 'Creating payment order...',
-        'redirect_stripe' => 'Redirect to Stripe ...',
+        'redirect_stripe' => 'Redirect to Stripe',
         'qrcode_tips'     => 'Please using <strong class="red-600">:software</strong> to scan QrCode',
         'close_tips'      => 'Please complete payment in <code>:minutes minutes</code>, otherwise it will be auto-closed by system',
         'mobile_tips'     => '<strong>Mobile User</strong>:Press QrCode image for a short amount of time -> Save Images -> Open payment software -> Scan it',

+ 1 - 0
resources/lang/zh_CN/common.php

@@ -77,6 +77,7 @@ return [
         'wechat' => '微信',
         'alipay' => '支付宝',
         'crypto' => '虚拟货币',
+        'manual' => '人工支付',
     ],
     'recommend'      => '推荐',
     'advance'        => '进阶',

+ 1 - 1
resources/lang/zh_CN/user.php

@@ -174,7 +174,7 @@ return [
     'payment'             => [
         'error'           => '充值余额不合规',
         'creating'        => '创建支付单中...',
-        'redirect_stripe' => '转跳至Stripe支付界面...',
+        'redirect_stripe' => '转跳至Stripe支付界面',
         'qrcode_tips'     => '请使用<strong class="red-600">:software</strong>扫描二维码',
         'close_tips'      => '请在<code>:minutes分钟</code>内完成支付,否则订单将会自动关闭',
         'mobile_tips'     => '<strong>手机用户</strong>:长按二维码 -> 保存图片 ->打开支付软件 -> 扫一扫 -> 选择相册 进行付款',

+ 27 - 0
resources/views/admin/config/system.blade.php

@@ -348,6 +348,29 @@
                                     <x-system.input title="商家ID" :value="$theadpay_mchid" code="theadpay_mchid"/>
                                     <x-system.input title="商家密钥" :value="$theadpay_key" code="theadpay_key"/>
                                 </x-system.tab-pane>
+                                <x-system.tab-pane id="Manual">
+                                    <div class="form-group col-lg-12 d-flex">
+                                        <label class="col-md-3 col-form-label">人工支付</label>
+                                        <div class="col-md-7">
+                                            设置后会自动开启对应显示
+                                        </div>
+                                    </div>
+                                    <div class="col-12">
+                                        @if($errors->any())
+                                            <x-alert type="danger" :message="$errors->all()"/>
+                                        @endif
+                                        @if (Session::has('successMsg'))
+                                            <x-alert type="success" :message="Session::get('successMsg')"/>
+                                        @endif
+                                    </div>
+                                    <x-system.input title="支付宝二维码" :value="$alipay_qrcode" code="alipay_qrcode" type="url"/>
+                                    <x-system.input title="微 信二维码" :value="$wechat_qrcode" code="wechat_qrcode" type="url"/>
+                                    <form action="{{route('admin.system.extend')}}" method="post" enctype="multipart/form-data" class="upload-form col-lg-12 row" role="form"
+                                          id="setExtend">@csrf
+                                        <x-system.input-file title="支付宝二维码" code="alipay_qrcode" :value="$alipay_qrcode"/>
+                                        <x-system.input-file title="微 信二维码" code="wechat_qrcode" :value="$wechat_qrcode"/>
+                                    </form>
+                                </x-system.tab-pane>
                             </div>
                             <ul class="nav nav-tabs nav-tabs-bottom nav-tabs-line dropup" role="tablist">
                                 <li class="nav-item">
@@ -380,6 +403,9 @@
                                 <li class="nav-item">
                                     <a class="nav-link" data-toggle="tab" href="#THeadPay" aria-controls="THeadPay" role="tab">平头哥支付</a>
                                 </li>
+                                <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#Manual" aria-controls="Manual" role="tab">人工支付</a>
+                                </li>
                                 <li class="nav-item dropdown" style="display: none;">
                                     <a class="dropdown-toggle nav-link" data-toggle="dropdown" href="#" aria-expanded="false" aria-haspopup="true">菜单</a>
                                     <div class="dropdown-menu" role="menu">
@@ -393,6 +419,7 @@
                                         <a class="dropdown-item" data-toggle="tab" href="#Stripe" aria-controls="Stripe" role="tab">Stripe</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#PayBeaver" aria-controls="PayBeaver" role="tab">PayBeaver</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#THeadPay" aria-controls="THeadPay" role="tab">平头哥支付</a>
+                                        <a class="dropdown-item" data-toggle="tab" href="#Manual" aria-controls="Manual" role="tab">人工支付</a>
                                     </div>
                                 </li>
                             </ul>

+ 44 - 12
resources/views/admin/logs/order.blade.php

@@ -78,13 +78,16 @@
                         <th> 用户账号</th>
                         <th> @sortablelink('sn', '订单号')</th>
                         <th> 商品</th>
-                        <th> @sortablelink('expired_at', '过期时间')</th>
                         <th> 优惠券</th>
                         <th> 原价</th>
                         <th> 实价</th>
                         <th> 支付方式</th>
                         <th> 订单状态</th>
+                        <th> @sortablelink('expired_at', '过期时间')</th>
                         <th> @sortablelink('created_at', '创建时间')</th>
+                        @can(['admin.order.edit'])
+                            <th> 操作</th>
+                        @endcan
                     </tr>
                     </thead>
                     <tbody>
@@ -104,25 +107,41 @@
                             </td>
                             <td> {{$order->sn}}</td>
                             <td> {{$order->goods->name  ?? trans('user.recharge_credit')}} </td>
-                            <td> {{$order->is_expire ? '已过期' : $order->expired_at}} </td>
                             <td> {{$order->coupon ? $order->coupon->name . ' - ' . $order->coupon->sn : ''}} </td>
                             <td> ¥{{$order->origin_amount}} </td>
                             <td> ¥{{$order->amount}} </td>
                             <td>
-                                <span class="badge badge-lg badge-info"> {{$order->pay_way_label}} </span>
+                                {{$order->pay_way_label}}
                             </td>
                             <td>
-                                @if($order->status === -1)
-                                    <span class="badge badge-lg badge-danger"> 已关闭 </span>
-                                @elseif ($order->status === 0)
-                                    <span class="badge badge-lg badge-default"> 待支付 </span>
-                                @elseif ($order->status === 1)
-                                    <span class="badge badge-lg badge-default"> 已支付待确认 </span>
-                                @else
-                                    <span class="badge badge-lg badge-success"> 已完成 </span>
-                                @endif
+                                {!! $order->status_label !!}
                             </td>
+                            <td> {{$order->is_expire ? '已过期' : $order->expired_at}} </td>
                             <td> {{$order->created_at}} </td>
+                            @can(['admin.order.edit'])
+                                <td>
+                                    <button type="button" class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" aria-expanded="false">
+                                        <i class="icon wb-wrench" aria-hidden="true"></i>
+                                    </button>
+                                    <div class="dropdown-menu" role="menu">
+                                        @if ($order->status !== -1)
+                                            <a class="dropdown-item" href="javascript:changeStatus('{{$order->id}}', -1)" role="menuitem">
+                                                <i class="icon wb-close" aria-hidden="true"></i> 置 过 期
+                                            </a>
+                                        @endif
+                                        @if ($order->status !== 2)
+                                            <a class="dropdown-item" href="javascript:changeStatus('{{$order->id}}', 2)" role="menuitem">
+                                                <i class="icon wb-check" aria-hidden="true"></i> 置 完 成
+                                            </a>
+                                        @endif
+                                        @if ($order->status !== 3)
+                                            <a class="dropdown-item" href="javascript:changeStatus('{{$order->id}}', 3)" role="menuitem">
+                                                <i class="icon wb-check-circle" aria-hidden="true"></i> 置 预支付
+                                            </a>
+                                        @endif
+                                    </div>
+                                </td>
+                            @endcan
                         </tr>
                     @endforeach
                     </tbody>
@@ -160,5 +179,18 @@
 
         // 有效期
         $('.input-daterange').datepicker({format: 'yyyy-mm-dd'});
+
+        @can('admin.order.edit')
+        // 重置流量
+        function changeStatus(id, status) {
+            $.post('{{route('admin.order.edit')}}', {_token: '{{csrf_token()}}', oid: id, status: status}, function(ret) {
+                if (ret.status === 'success') {
+                    swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
+                } else {
+                    swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+                }
+            });
+        }
+        @endcan
     </script>
 @endsection

+ 41 - 43
resources/views/admin/node/index.blade.php

@@ -75,51 +75,49 @@
                             </td>
                             <td>
                                 @canany(['admin.node.edit', 'admin.node.destroy', 'admin.node.monitor', 'admin.node.geo', 'admin.node.ping', 'admin.node.check', 'admin.node.reload'])
-                                    <div class="btn-group" role="group">
-                                        <button type="button" class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" aria-expanded="false">
-                                            <i class="icon wb-wrench" aria-hidden="true"></i>
-                                        </button>
-                                        <div class="dropdown-menu" role="menu">
-                                            @can('admin.node.edit')
-                                                <a class="dropdown-item" href="{{route('admin.node.edit', [$node->id, 'page' => Request::query('page', 1)])}}" role="menuitem">
-                                                    <i class="icon wb-edit" aria-hidden="true"></i> 编辑
+                                    <button type="button" class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" aria-expanded="false">
+                                        <i class="icon wb-wrench" aria-hidden="true"></i>
+                                    </button>
+                                    <div class="dropdown-menu" role="menu">
+                                        @can('admin.node.edit')
+                                            <a class="dropdown-item" href="{{route('admin.node.edit', [$node->id, 'page' => Request::query('page', 1)])}}" role="menuitem">
+                                                <i class="icon wb-edit" aria-hidden="true"></i> 编辑
+                                            </a>
+                                        @endcan
+                                        @can('admin.node.destroy')
+                                            <a class="dropdown-item" href="javascript:delNode('{{$node->id}}', '{{$node->name}}')" role="menuitem">
+                                                <i class="icon wb-trash" aria-hidden="true"></i> 删除
+                                            </a>
+                                        @endcan
+                                        @can('admin.node.monitor')
+                                            <a class="dropdown-item" href="{{route('admin.node.monitor', $node)}}" role="menuitem">
+                                                <i class="icon wb-stats-bars" aria-hidden="true"></i> 流量统计
+                                            </a>
+                                        @endcan
+                                        <hr/>
+                                        @can('admin.node.geo')
+                                            <a class="dropdown-item" href="javascript:refreshGeo('{{$node->id}}')" role="menuitem">
+                                                <i id="geo{{$node->id}}" class="icon wb-map" aria-hidden="true"></i> 刷新地理
+                                            </a>
+                                        @endcan
+                                        @can('admin.node.ping')
+                                            <a class="dropdown-item" href="javascript:pingNode('{{$node->id}}')" role="menuitem">
+                                                <i id="ping{{$node->id}}" class="icon wb-order" aria-hidden="true"></i> 检测延迟
+                                            </a>
+                                        @endcan
+                                        @can('admin.node.check')
+                                            <a class="dropdown-item" href="javascript:checkNode('{{$node->id}}')" role="menuitem">
+                                                <i id="node{{$node->id}}" class="icon wb-signal" aria-hidden="true"></i> 连通性检测
+                                            </a>
+                                        @endcan
+                                        @if($node->type === 4)
+                                            @can('admin.node.reload')
+                                                <hr/>
+                                                <a class="dropdown-item" href="javascript:reload('{{$node->id}}')" role="menuitem">
+                                                    <i id="reload{{$node->id}}" class="icon wb-reload" aria-hidden="true"></i> 重载后端
                                                 </a>
                                             @endcan
-                                            @can('admin.node.destroy')
-                                                <a class="dropdown-item" href="javascript:delNode('{{$node->id}}', '{{$node->name}}')" role="menuitem">
-                                                    <i class="icon wb-trash" aria-hidden="true"></i> 删除
-                                                </a>
-                                            @endcan
-                                            @can('admin.node.monitor')
-                                                <a class="dropdown-item" href="{{route('admin.node.monitor', $node)}}" role="menuitem">
-                                                    <i class="icon wb-stats-bars" aria-hidden="true"></i> 流量统计
-                                                </a>
-                                            @endcan
-                                            <hr/>
-                                            @can('admin.node.geo')
-                                                <a class="dropdown-item" href="javascript:refreshGeo('{{$node->id}}')" role="menuitem">
-                                                    <i id="geo{{$node->id}}" class="icon wb-map" aria-hidden="true"></i> 刷新地理
-                                                </a>
-                                            @endcan
-                                            @can('admin.node.ping')
-                                                <a class="dropdown-item" href="javascript:pingNode('{{$node->id}}')" role="menuitem">
-                                                    <i id="ping{{$node->id}}" class="icon wb-order" aria-hidden="true"></i> 检测延迟
-                                                </a>
-                                            @endcan
-                                            @can('admin.node.check')
-                                                <a class="dropdown-item" href="javascript:checkNode('{{$node->id}}')" role="menuitem">
-                                                    <i id="node{{$node->id}}" class="icon wb-signal" aria-hidden="true"></i> 连通性检测
-                                                </a>
-                                            @endcan
-                                            @if($node->type === 4)
-                                                @can('admin.node.reload')
-                                                    <hr/>
-                                                    <a class="dropdown-item" href="javascript:reload('{{$node->id}}')" role="menuitem">
-                                                        <i id="reload{{$node->id}}" class="icon wb-reload" aria-hidden="true"></i> 重载后端
-                                                    </a>
-                                                @endcan
-                                            @endif
-                                        </div>
+                                        @endif
                                     </div>
                                 @endcan
                             </td>

+ 39 - 41
resources/views/admin/user/index.blade.php

@@ -147,47 +147,45 @@
                             </td>
                             <td>
                                 @canany(['admin.user.edit', 'admin.user.destroy', 'admin.user.export', 'admin.user.monitor', 'admin.user.online', 'admin.user.reset', 'admin.user.switch'])
-                                    <div class="btn-group" role="group">
-                                        <button type="button" class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" aria-expanded="false">
-                                            <i class="icon wb-wrench" aria-hidden="true"></i>
-                                        </button>
-                                        <div class="dropdown-menu" role="menu">
-                                            @can('admin.user.edit')
-                                                <a class="dropdown-item" href="{{route('admin.user.edit', ['user'=>$user->id, Request::getQueryString()])}}" role="menuitem">
-                                                    <i class="icon wb-edit" aria-hidden="true"></i> 编辑
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.destroy')
-                                                <a class="dropdown-item" href="javascript:delUser('{{route('admin.user.destroy', $user->id)}}','{{$user->username}}')" role="menuitem">
-                                                    <i class="icon wb-trash" aria-hidden="true"></i> 删除
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.export')
-                                                <a class="dropdown-item" href="{{route('admin.user.export', $user)}}" role="menuitem">
-                                                    <i class="icon wb-code" aria-hidden="true"></i> 配置信息
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.monitor')
-                                                <a class="dropdown-item" href="{{route('admin.user.monitor', $user)}}" role="menuitem">
-                                                    <i class="icon wb-stats-bars" aria-hidden="true"></i> 流量统计
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.online')
-                                                <a class="dropdown-item" href="{{route('admin.user.online', $user)}}" role="menuitem">
-                                                    <i class="icon wb-cloud" aria-hidden="true"></i> 在线巡查
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.reset')
-                                                <a class="dropdown-item" href="javascript:resetTraffic('{{$user->id}}','{{$user->username}}')" role="menuitem">
-                                                    <i class="icon wb-reload" aria-hidden="true"></i> 重置流量
-                                                </a>
-                                            @endcan
-                                            @can('admin.user.switch')
-                                                <a class="dropdown-item" href="javascript:switchToUser('{{$user->id}}')" role="menuitem">
-                                                    <i class="icon wb-user" aria-hidden="true"></i> 用户视角
-                                                </a>
-                                            @endcan
-                                        </div>
+                                    <button type="button" class="btn btn-primary dropdown-toggle" data-boundary="viewport" data-toggle="dropdown" aria-expanded="false">
+                                        <i class="icon wb-wrench" aria-hidden="true"></i>
+                                    </button>
+                                    <div class="dropdown-menu" role="menu">
+                                        @can('admin.user.edit')
+                                            <a class="dropdown-item" href="{{route('admin.user.edit', ['user'=>$user->id, Request::getQueryString()])}}" role="menuitem">
+                                                <i class="icon wb-edit" aria-hidden="true"></i> 编辑
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.destroy')
+                                            <a class="dropdown-item" href="javascript:delUser('{{route('admin.user.destroy', $user->id)}}','{{$user->username}}')" role="menuitem">
+                                                <i class="icon wb-trash" aria-hidden="true"></i> 删除
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.export')
+                                            <a class="dropdown-item" href="{{route('admin.user.export', $user)}}" role="menuitem">
+                                                <i class="icon wb-code" aria-hidden="true"></i> 配置信息
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.monitor')
+                                            <a class="dropdown-item" href="{{route('admin.user.monitor', $user)}}" role="menuitem">
+                                                <i class="icon wb-stats-bars" aria-hidden="true"></i> 流量统计
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.online')
+                                            <a class="dropdown-item" href="{{route('admin.user.online', $user)}}" role="menuitem">
+                                                <i class="icon wb-cloud" aria-hidden="true"></i> 在线巡查
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.reset')
+                                            <a class="dropdown-item" href="javascript:resetTraffic('{{$user->id}}','{{$user->username}}')" role="menuitem">
+                                                <i class="icon wb-reload" aria-hidden="true"></i> 重置流量
+                                            </a>
+                                        @endcan
+                                        @can('admin.user.switch')
+                                            <a class="dropdown-item" href="javascript:switchToUser('{{$user->id}}')" role="menuitem">
+                                                <i class="icon wb-user" aria-hidden="true"></i> 用户视角
+                                            </a>
+                                        @endcan
                                     </div>
                                 @endcanany
                             </td>

+ 0 - 0
resources/views/user/payment.blade.php → resources/views/user/components/payment/default.blade.php


+ 212 - 0
resources/views/user/components/payment/manual.blade.php

@@ -0,0 +1,212 @@
+@extends('user.layouts')
+
+@section('css')
+    <style>
+        .tab {
+            display: none;
+        }
+
+        .hide {
+            display: none;
+        }
+    </style>
+@endsection
+
+@section('content')
+    <div class="page-content container">
+        <div class="panel panel-bordered">
+            <div class="panel-heading">
+                <h1 class="panel-title cyan-600">
+                    <i class="icon wb-payment"></i>{{sysConfig('website_name').' '.trans('common.payment.manual')}}
+                </h1>
+            </div>
+            <div class="panel-body border-primary">
+                <div class="steps row w-p100">
+                    <div class="step col-lg-4 current">
+                        <span class="step-number">1</span>
+                        <div class="step-desc">
+                            <span class="step-title">须知</span>
+                            <p>如何正确使用本支付</p>
+                        </div>
+                    </div>
+                    <div class="step col-lg-4">
+                        <span class="step-number">2</span>
+                        <div class="step-desc">
+                            <span class="step-title">支付</span>
+                            <p>获取支付二维码,进行支付</p>
+                        </div>
+                    </div>
+                    <div class="step col-lg-4">
+                        <span class="step-number">3</span>
+                        <div class="step-desc">
+                            <span class="step-title">等待</span>
+                            <p>等待支付被确认</p>
+                        </div>
+                    </div>
+                </div>
+
+                <div id="payment-group" class="w-p100 text-center mb-20">
+                    <div class="w-md-p50 w-p100 mx-auto btn-group">
+                        @if(sysConfig('wechat_qrcode'))
+                            <button id="btn-wechat" class="btn btn-lg btn-block" onclick="show(0)">{{trans('common.payment.wechat')}}</button>
+                        @endif
+                        @if(sysConfig('alipay_qrcode'))
+                            <button id="btn-alipay" class="btn mt-0 btn-lg btn-block" onclick="show(1)">{{trans('common.payment.alipay')}}</button>
+                        @endif
+                    </div>
+                </div>
+                <div class="tab">
+                    <div class="wechat hide">
+                        <div class="mx-auto text-center">
+                            <h4>备注账号</h4>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset('assets/images/help/manual_wechat1.png')}}" alt=""/>
+                            <h4>填入登录使用的账号</h4>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset('assets/images/help/manual_wechat2.png')}}" alt=""/>
+                        </div>
+                    </div>
+                    <div class="alipay hide">
+                        <div class="mx-auto text-center">
+                            <h5>备注1账号</h5>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset('assets/images/help/manual_wechat1.png')}}" alt=""/>
+                            <h5>填入登录使用的账号</h5>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset('assets/images/help/manual_wechat2.png')}}" alt=""/>
+                        </div>
+                    </div>
+                </div>
+
+                <div class="tab">
+                    <div class="wechat hide">
+                        <div class="mx-auto text-center">
+                            <div class="alert alert-info">
+                                {!! trans('user.payment.qrcode_tips', ['software' => trans('common.payment.wechat')]) !!}
+                            </div>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset(sysConfig('wechat_qrcode'))}}" alt=""/>
+                        </div>
+                    </div>
+                    <div class="alipay hide">
+                        <div class="mx-auto text-center">
+                            <div class="alert alert-info">
+                                {!! trans('user.payment.qrcode_tips', ['software' => trans('common.payment.alipay')]) !!}
+                            </div>
+                            <p>{{trans('common.payment.alipay')}}</p>
+                            <img class="w-lg-350 w-md-p50 w-p100 mb-10" src="{{asset(sysConfig('alipay_qrcode'))}}" alt=""/>
+                        </div>
+                    </div>
+                    <div class="alert alert-danger text-center">
+                        {!! trans('user.payment.mobile_tips') !!}
+                    </div>
+                </div>
+
+                <div class="tab">
+                    <div class="alert alert-danger text-center">
+                        支付时,请充值正确金额(多不退,少要补)
+                    </div>
+                    <div class="mx-auto w-md-p50">
+                        <ul class="list-group list-group-dividered">
+                            <li class="list-group-item">{{trans('user.shop.service').':'.$name}}</li>
+                            <li class="list-group-item">{{trans('user.shop.price').':¥'.$payment->amount}}</li>
+                            @if($days !== 0)
+                                <li class="list-group-item">{{trans('common.available_date').':'.$days.trans_choice('validation.attributes.day', 1)}}</li>
+                            @endif
+                        </ul>
+                    </div>
+                </div>
+
+                <div class="clearfix">
+                    <button type="button" class="btn btn-lg btn-default float-left" id="prevBtn" onclick="nextPrev(-1)">上一步</button>
+                    <button type="button" class="btn btn-lg btn-default float-right" id="nextBtn" onclick="nextPrev(1)">下一步</button>
+                </div>
+            </div>
+        </div>
+    </div>
+@endsection
+
+@section('javascript')
+    <script>
+        let currentTab = 0; // Current tab is set to be the first tab (0)
+        showTab(currentTab); // Display the current tab
+        show(0);
+
+        function showTab(n) {
+            // This function will display the specified tab of the form ...
+            const x = document.getElementsByClassName('tab');
+            x[n].style.display = 'block';
+            // ... and fix the Previous/Next buttons:
+            if (n === 0) {
+                document.getElementById('prevBtn').style.display = 'none';
+            } else {
+                document.getElementById('prevBtn').style.display = 'inline';
+            }
+
+            if (n === x.length - 1) {
+                document.getElementById('payment-group').style.display = 'none';
+                document.getElementById('nextBtn').classList.remove('btn-default');
+                document.getElementById('nextBtn').classList.add('btn-primary');
+                document.getElementById('nextBtn').innerHTML = '{{trans('user.status.completed')}}';
+            } else {
+                document.getElementById('payment-group').style.display = 'inline-flex';
+                document.getElementById('nextBtn').innerHTML = '下一步';
+                document.getElementById('nextBtn').style.display = 'inline';
+            }
+
+            fixStepIndicator(n);
+        }
+
+        function nextPrev(n) {
+            // This function will figure out which tab to display
+            const x = document.getElementsByClassName('tab');
+            // Hide the current tab:
+            x[currentTab].style.display = 'none';
+            // Increase or decrease the current tab by 1:
+            currentTab += n;
+
+            // if you have reached the end of the form... :
+            if (currentTab >= x.length) {
+                //...the form gets submitted:
+                $.post('{{route('manual.inform', ['payment' => $payment->trade_no])}}', {_token: '{{csrf_token()}}'}, function(ret) {
+                    if (ret.status === 'success') {
+                        swal.fire({title: '已受理', text: ret.message, icon: 'success'}).then(() => window.location.href = '{{route('invoice')}}');
+                    } else {
+                        swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+                    }
+                });
+                return false;
+            } else {
+                showTab(currentTab);
+            }
+
+        }
+
+        function fixStepIndicator(n) {
+            // This function removes the "current" class of all steps...
+            let i, x = document.getElementsByClassName('step');
+            for (i = 0; i < x.length; i++) {
+                x[i].className = x[i].className.replace(' current', ' ');
+            }
+            //... and adds the "active" class to the current step:
+            x[n].className += ' current';
+        }
+
+        function show(check) {
+            const $wechat = document.getElementsByClassName('wechat');
+            const $btn_wechat = document.getElementById('btn-wechat');
+            const $alipay = document.getElementsByClassName('alipay');
+            const $btn_alipay = document.getElementById('btn-alipay');
+            if (check) {
+                for (let i = 0; i < $wechat.length; i++) {
+                    $wechat[i].style.display = 'none';
+                    $alipay[i].style.display = 'inline';
+                }
+                $btn_wechat.classList.remove('btn-success');
+                $btn_alipay.classList.add('btn-primary');
+            } else {
+                for (let i = 0; i < $wechat.length; i++) {
+                    $wechat[i].style.display = 'inline';
+                    $alipay[i].style.display = 'none';
+                }
+                $btn_wechat.classList.add('btn-success');
+                $btn_alipay.classList.remove('btn-primary');
+            }
+        }
+    </script>
+@endsection

+ 19 - 0
resources/views/user/components/payment/stripe.blade.php

@@ -0,0 +1,19 @@
+@extends('_layout')
+@section('title', sysConfig('website_name'))
+@section('body_class','page-login-v3 layout-full')
+@section('layout_content')
+    <div class="page vertical-align text-center" data-animsition-in="fade-in" data-animsition-out="fade-out">>
+        <div class="page-content vertical-align-middle">
+            <h2>{{trans('user.payment.redirect_stripe')}}</h2>
+            <i class="mt-30 loader loader-ellipsis"></i>
+        </div>
+    </div>
+@endsection
+
+@section('layout_javascript')
+    <script src="https://js.stripe.com/v3/"></script>
+    <script>
+        let stripe = Stripe('{{ sysConfig('stripe_public_key') }}');
+        let redirectData = stripe.redirectToCheckout({sessionId: '{{ $session_id  }}'});
+    </script>
+@endsection

+ 5 - 0
resources/views/user/components/purchase.blade.php

@@ -29,3 +29,8 @@
         <img src="/assets/images/payment/stripe.svg" height="40px" alt="stripe"/>
     </button>
 @endif
+@if(sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
+    <button class="btn btn-round btn-outline-default mt-2" onclick="pay('manual','7')">
+        <img src="/assets/images/payment/pay.svg" height="40px" alt="pay"/> <span class="font-size-18 font-weight-bold"> 人工支付 </span>
+    </button>
+@endif

+ 7 - 41
resources/views/user/services.blade.php

@@ -112,17 +112,14 @@
                         @if(sysConfig('is_onlinePay') || sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
                             <div class="mb-15 w-p50">
                                 <select class="form-control" name="charge_type" id="charge_type">
-                                    @if(sysConfig('is_onlinePay'))
+                                    @if(sysConfig('is_onlinePay') || sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
                                         <option value="1">{{trans('user.shop.pay_online')}}</option>
                                     @endif
-                                    @if(sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
-                                        <option value="2">{{trans('common.qrcode', ['attribute' => ''])}}</option>
-                                    @endif
-                                    <option value="3">{{trans('user.coupon.recharge')}}</option>
+                                    <option value="2">{{trans('user.coupon.recharge')}}</option>
                                 </select>
                             </div>
                         @endif
-                        @if(sysConfig('is_onlinePay'))
+                        @if(sysConfig('is_onlinePay') || sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
                             <div class="form-group row charge_credit">
                                 <label for="amount" class="offset-md-1 col-md-2 col-form-label">{{trans('user.shop.change_amount')}}</label>
                                 <div class="col-md-8">
@@ -130,28 +127,6 @@
                                 </div>
                             </div>
                         @endif
-                        @if(sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
-                            <div class="text-center" id="charge_qrcode">
-                                <div class="row">
-                                    <p class="col-md-12 mb-10">付款时,请
-                                        <mark>备注邮箱账号</mark>
-                                        ,充值会在<code>24</code>小时内受理!
-                                    </p>
-                                    @if(sysConfig('wechat_qrcode'))
-                                        <div class="col-md-6">
-                                            <img class="w-p75 mb-10" src="{{sysConfig('wechat_qrcode')}}" alt=""/>
-                                            <p>{{trans('common.payment.wechat')}}</p>
-                                        </div>
-                                    @endif
-                                    @if(sysConfig('alipay_qrcode'))
-                                        <div class="col-md-6">
-                                            <img class="w-p75 mb-10" src="{{sysConfig('alipay_qrcode')}}" alt=""/>
-                                            <p>{{trans('common.payment.alipay')}}</p>
-                                        </div>
-                                    @endif
-                                </div>
-                            </div>
-                        @endif
                         <div class="form-group row" id="charge_coupon_code">
                             <label for="charge_coupon"
                                    class="offset-md-2 col-md-2 col-form-label"> {{trans('user.coupon.recharge')}} </label>
@@ -179,27 +154,18 @@
             if (value === 1) {
                 $('.charge_credit').show();
                 $('#change_btn').hide();
-                $('#charge_qrcode').hide();
-                $('#charge_coupon_code').hide();
-            } else if (value === 2) {
-                $('.charge_credit').hide();
-                $('#change_btn').hide();
-                $('#charge_qrcode').show();
                 $('#charge_coupon_code').hide();
             } else {
                 $('.charge_credit').hide();
-                $('#charge_qrcode').hide();
                 $('#charge_coupon_code').show();
                 $('#change_btn').show();
             }
         }
 
         $(document).ready(function() {
-            let which_selected = 3;
-            @if(sysConfig('is_onlinePay'))
+            let which_selected = 2;
+            @if(sysConfig('is_onlinePay') || sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
                 which_selected = 1;
-            @elseif(sysConfig('alipay_qrcode') || sysConfig('wechat_qrcode'))
-                which_selected = 2;
             @endif
 
             itemControl(which_selected);
@@ -239,7 +205,7 @@
 
         // 充值
         function pay(method, pay_type) {
-            const paymentType = parseInt($('#charge_type').val() ?? 3);
+            const paymentType = parseInt($('#charge_type').val() ?? 2);
             const charge_coupon = $('#charge_coupon').val().trim();
             const amount = parseInt($('#amount').val());
             if (paymentType === 1) {
@@ -272,7 +238,7 @@
                         $('#charge_msg').show().html("{{trans('user.error_response')}}");
                     },
                 });
-            } else if (paymentType === 3) {
+            } else if (paymentType === 2) {
                 if (charge_coupon === '') {
                     $('#charge_msg').show().html("{{trans('validation.required', ['attribute' => trans('user.coupon.attribute')])}}");
                     $('#charge_coupon').focus();

+ 0 - 18
resources/views/user/stripe-checkout.blade.php

@@ -1,18 +0,0 @@
-@extends('user.layouts')
-
-@section('css')
-@endsection
-
-@section('content')
-    <div>
-        <p style="text-align: center">{{trans('user.payment.redirect_stripe')}}</p>
-    </div>
-@endsection
-
-@section('javascript')
-    <script src="https://js.stripe.com/v3/"></script>
-    <script>
-        let stripe = Stripe('{{ sysConfig('stripe_public_key') }}');
-        let redirectData = stripe.redirectToCheckout({sessionId: '{{ $session_id  }}'});
-    </script>
-@endsection

+ 1 - 0
routes/admin.php

@@ -68,6 +68,7 @@ Route::prefix('admin')->name('admin.')->group(function () {
         });
 
         Route::get('order', 'LogsController@orderList')->name('order'); // 订单列表
+        Route::post('order/edit', 'LogsController@changeOrderStatus')->name('order.edit'); // 订单列表
 
         Route::prefix('report')->name('report.')->group(function () {
             Route::get('accounting', 'ReportController@accounting')->name('accounting'); // 流水账簿

+ 6 - 1
routes/user.php

@@ -35,4 +35,9 @@ Route::prefix('payment')->group(function () {
     Route::get('{trade_no}', 'PaymentController@detail')->name('orderDetail'); // 支付单详情
 });
 
-Route::get('/stripe-checkout/{session_id}', 'Gateway\Stripe@redirectPage')->name('stripe-checkout'); // Stripe Checkout page
+Route::prefix('pay')->group(function () {
+    Route::get('/manual/{payment}', 'Gateway\Manual@redirectPage')->name('manual.checkout'); // 人工支付详细
+    Route::post('/manual/{payment}/inform', 'Gateway\Manual@inform')->name('manual.inform'); // 人工支付通知
+
+    Route::get('/stripe/{session_id}', 'Gateway\Stripe@redirectPage')->name('stripe.checkout'); // Stripe Checkout page
+});

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels