Browse Source

Add 3 more notification methods

添加通知方式:
- 爱语飞飞;
- PushDear;
- 钉钉;

去除 PushBear;
兔姬桑 3 years ago
parent
commit
cce0799350

+ 1 - 1
app/Channels/BarkChannel.php

@@ -42,7 +42,7 @@ class BarkChannel
             return false;
         }
         // 发送错误
-        Log::critical('Bark消息推送异常:'.var_export($response, true));
+        Log::critical('[Bark] 消息推送异常:'.var_export($response, true));
 
         return false;
     }

+ 106 - 0
app/Channels/DingTalkChannel.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Channels;
+
+use Cache;
+use Helpers;
+use Http;
+use Illuminate\Notifications\Notification;
+use Log;
+use Str;
+
+class DingTalkChannel
+{
+    // https://open.dingtalk.com/document/robots/custom-robot-access
+    public function send($notifiable, Notification $notification)
+    {
+        $cacheKey = 'dingTalkCount'.date('d');
+        if (Cache::has($cacheKey)) {
+            Cache::increment($cacheKey);
+        } else {
+            Cache::put($cacheKey, 1, Minute); // 1分钟
+        }
+
+        if (Cache::get($cacheKey) > 20) { // 每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。
+            Log::critical('[钉钉] 消息推送异常:每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。');
+
+            return false;
+        }
+
+        $message = $notification->toCustom($notifiable);
+
+        $url = 'https://oapi.dingtalk.com/robot/send?';
+
+        $query['access_token'] = sysConfig('dingTalk_access_token');
+
+        if (sysConfig('dingTalk_secret') !== null) {
+            $timestamp = time() * 1000;
+            $query['timestamp'] = $timestamp;
+            $query['sign'] = $this->sign($timestamp);
+        }
+        $url .= http_build_query($query);
+
+        if (isset($message['button'])) { // 独立跳转ActionCard类型
+            $body = [
+                'msgtype'    => 'actionCard',
+                'actionCard' => [
+                    'title'          => $message['title'],
+                    'text'           => $message['markdown'],
+                    'btnOrientation' => 1,
+                    'btns'           => [
+                        [
+                            'title'     => '否 決',
+                            'actionURL' => $message['button'][0],
+                        ],
+                        [
+                            'title'     => '确 认',
+                            'actionURL' => $message['button'][1],
+                        ],
+                    ],
+                ],
+            ];
+        } elseif (isset($message['url_type'])) { // 文本卡片
+            $msgId = Str::uuid(); // 生成对公消息查询URL
+            $body = [
+                'msgtype' => 'link',
+                'link'    => [
+                    'title'      => $message['title'],
+                    'text'       => '请点击下方按钮【查看详情】',
+                    'messageUrl' => route('message.show', ['type' => $message['url_type'], $msgId]),
+                ],
+            ];
+        } else { // 文本消息
+            $body = [
+                'msgtype' => 'text',
+                'text'    => [
+                    'content' => $message['content'],
+                ],
+            ];
+        }
+
+        $response = Http::timeout(15)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json;charset=utf-8')->post($url);
+
+        // 发送成功
+        if ($response->ok()) {
+            $ret = $response->json();
+            if (! $ret['errcode'] && $ret['errmsg'] === 'ok') {
+                Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, 1, null, $msgId ?? null);
+
+                return $ret;
+            }
+            // 发送失败
+            Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, -1, $ret ? $ret['errmsg'] : '未知');
+
+            return false;
+        }
+        // 发送错误
+        Log::critical('[钉钉] 消息推送异常:'.var_export($response, true));
+
+        return false;
+    }
+
+    private function sign(int $timestamp): string // 加签
+    { // https://open.dingtalk.com/document/robots/customize-robot-security-settings
+        return base64_encode(hash_hmac('sha256', $timestamp."\n".sysConfig('dingTalk_secret'), sysConfig('dingTalk_secret'), true));
+    }
+}

+ 0 - 38
app/Channels/PushBearChannel.php

@@ -1,38 +0,0 @@
-<?php
-
-namespace App\Channels;
-
-use Helpers;
-use Http;
-use Illuminate\Notifications\Notification;
-use Log;
-
-class PushBearChannel
-{
-    public function send($notifiable, Notification $notification)
-    {
-        $message = $notification->toCustom($notifiable);
-        $response = Http::timeout(15)->get('https://pushbear.ftqq.com/sub', [
-            'sendkey' => sysConfig('push_bear_send_key'),
-            'text'    => $message['title'],
-            'desp'    => $message['content'],
-        ]);
-        if ($response->ok()) {
-            $ret = $response->json();
-            // 发送成功
-            if ($ret) {
-                Helpers::addMarketing(2, $message['title'], $message['content']);
-
-                return $ret;
-            }
-            // 发送失败
-            Helpers::addMarketing(2, $message['title'], $message['content'], -1, '无返回内容');
-
-            return false;
-        }
-        // 发送错误
-        Log::critical('PushBear消息推送异常:'.var_export($response, true));
-
-        return false;
-    }
-}

+ 38 - 0
app/Channels/PushDeerChannel.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Channels;
+
+use Helpers;
+use Http;
+use Illuminate\Notifications\Notification;
+use Log;
+
+class PushDeerChannel
+{
+    public function send($notifiable, Notification $notification)
+    {
+        $message = $notification->toCustom($notifiable);
+
+        $response = Http::timeout(15)
+                ->post('https://api2.pushdeer.com/message/push?pushkey='.sysConfig('pushDeer_key').'&text='.urlencode($message['title']).'&desp='
+                    .urlencode($message['content']).'&type=markdown');
+
+        // 发送成功
+        if ($response->ok()) {
+            $ret = $response->json();
+            if (! $ret['code']) {
+                Helpers::addNotificationLog($message['title'], $message['content'], 9);
+
+                return $ret;
+            }
+            // 发送失败
+            Helpers::addNotificationLog($message['title'], $message['content'], 9, -1, $ret ? $ret['error'] : '未知');
+
+            return false;
+        }
+        // 发送错误
+        Log::critical('[PushDeer] 消息推送异常:'.var_export($response, true));
+
+        return false;
+    }
+}

+ 1 - 1
app/Channels/PushPlusChannel.php

@@ -35,7 +35,7 @@ class PushPlusChannel
             return false;
         }
         // 发送错误
-        Log::critical('PushPlus消息推送异常:'.var_export($response, true));
+        Log::critical('[PushPlus] 消息推送异常:'.var_export($response, true));
 
         return false;
     }

+ 22 - 10
app/Channels/ServerChanChannel.php

@@ -14,19 +14,31 @@ class ServerChanChannel
     {
         $message = $notification->toCustom($notifiable);
 
-        $cacheKey = 'serverChanCount'.date('d');
-        if (Cache::has($cacheKey)) {
-            Cache::increment($cacheKey);
+        $cacheDayKey = 'serverChanCountDays';
+        $cacheMinuteKey = 'serverChanCountMinutes';
+        if (Cache::has($cacheDayKey)) {
+            Cache::increment($cacheDayKey);
         } else {
-            Cache::put($cacheKey, 1, Day); // 24小时
+            Cache::put($cacheDayKey, 1, Day); // 天限制
         }
 
-        // 一天仅可发送不超过500条
-        if (Cache::get($cacheKey) < 500) {
-            $response = Http::timeout(15)
-                ->get('https://sctapi.ftqq.com/'.sysConfig('server_chan_key').'.send?title='.$message['title'].'&desp='.urlencode($message['content']));
+        if (Cache::has($cacheMinuteKey)) {
+            Cache::increment($cacheMinuteKey);
         } else {
-            Log::critical('ServerChan消息推送异常:今日500条限额已耗尽!');
+            Cache::put($cacheMinuteKey, 1, Minute); // 分钟限制
+        }
+
+        if (Cache::get($cacheDayKey) < 1000) { // 订阅会员 一天仅可发送不超过1000条
+            if (Cache::get($cacheMinuteKey) < 5) {
+                $response = Http::timeout(15)
+                    ->post('https://sctapi.ftqq.com/'.sysConfig('server_chan_key').'.send?title='.urlencode($message['title']).'&desp='.urlencode($message['content']));
+            } else {
+                Log::critical('[ServerChan] 消息推送异常:分钟频率过高,请优化通知场景!');
+
+                return false;
+            }
+        } else {
+            Log::critical('[ServerChan] 消息推送异常:今日限额已耗尽!');
 
             return false;
         }
@@ -45,7 +57,7 @@ class ServerChanChannel
             return false;
         }
         // 发送错误
-        Log::critical('ServerChan消息推送异常:'.var_export($response, true));
+        Log::critical('[ServerChan] 消息推送异常:'.var_export($response, true));
 
         return false;
     }

+ 1 - 1
app/Channels/TgChatChannel.php

@@ -29,7 +29,7 @@ class TgChatChannel
             return false;
         }
         // 发送错误
-        Log::critical('TG酱消息推送异常:'.var_export($response, true));
+        Log::critical('[TG酱] 消息推送异常:'.var_export($response, true));
 
         return false;
     }

+ 12 - 5
app/Channels/WeChatChannel.php

@@ -60,11 +60,18 @@ class WeChatChannel
                 ],
             ];
         } else { // 文本消息
-            $body = ['touser' => '@all', 'agentid' => sysConfig('wechat_aid'), 'msgtype' => 'text', 'text' => ['content' => $message['content']], 'duplicate_check_interval' => 600,
+            $body = [
+                'touser'                   => '@all',
+                'agentid'                  => sysConfig('wechat_aid'),
+                'msgtype'                  => 'text',
+                'text'                     => [
+                    'content' => $message['content'],
+                ],
+                'duplicate_check_interval' => 600,
             ];
         }
 
-        $response = Http::timeout(15)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json; charset=utf-8')->post($url);
+        $response = Http::timeout(15)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json;charset=utf-8')->post($url);
 
         // 发送成功
         if ($response->ok()) {
@@ -80,7 +87,7 @@ class WeChatChannel
             return false;
         }
         // 发送错误
-        Log::critical('Wechat消息推送异常:'.var_export($response, true));
+        Log::critical('[企业微信] 消息推送异常:'.var_export($response, true));
 
         return false;
     }
@@ -96,7 +103,7 @@ class WeChatChannel
                 $access_token = $response->json()['access_token'];
                 Cache::put('wechat_access_token', $access_token, 7189); // 2小时
             } else {
-                Log::critical('Wechat消息推送异常:获取access_token失败!'.PHP_EOL.'携带访问参数:'.$response->body());
+                Log::critical('[企业微信] 消息推送异常:获取access_token失败!'.PHP_EOL.'携带访问参数:'.$response->body());
                 abort(400);
             }
         }
@@ -111,6 +118,6 @@ class WeChatChannel
             exit($sEchoStr);
         }
 
-        Log::critical('Wechat互动消息推送异常:'.var_export($errCode, true));
+        Log::critical('[企业微信] 互动消息推送异常:'.var_export($errCode, true));
     }
 }

+ 37 - 0
app/Channels/iYuuChannel.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Channels;
+
+use Helpers;
+use Http;
+use Illuminate\Notifications\Notification;
+use Log;
+
+class iYuuChannel
+{
+    public function send($notifiable, Notification $notification)
+    {
+        $message = $notification->toCustom($notifiable);
+
+        $response = Http::timeout(15)
+            ->post('https://iyuu.cn/'.sysConfig('iYuu_token').'.send?title='.urlencode($message['title']).'&desp='.urlencode($message['content']));
+
+        // 发送成功
+        if ($response->ok()) {
+            $ret = $response->json();
+            if (! $ret['errcode']) {
+                Helpers::addNotificationLog($message['title'], $message['content'], 8);
+
+                return $ret;
+            }
+            // 发送失败
+            Helpers::addNotificationLog($message['title'], $message['content'], 8, -1, $ret ? $ret['errmsg'] : '未知');
+
+            return false;
+        }
+        // 发送错误
+        Log::critical('[爱语飞飞] 消息推送异常:'.var_export($response, true));
+
+        return false;
+    }
+}

+ 6 - 9
app/Http/Controllers/Admin/MarketingController.php

@@ -2,12 +2,9 @@
 
 namespace App\Http\Controllers\Admin;
 
-use App\Channels\PushBearChannel;
 use App\Http\Controllers\Controller;
 use App\Models\Marketing;
-use App\Notifications\Custom;
 use Illuminate\Http\Request;
-use Notification;
 use Response;
 
 class MarketingController extends Controller
@@ -42,12 +39,12 @@ class MarketingController extends Controller
         $title = $request->input('title');
         $content = $request->input('content');
 
-        if (! sysConfig('is_push_bear')) {
-            return Response::json(['status' => 'fail', 'message' => '推送失败:请先启用并配置PushBear']);
-        }
+//        if (! sysConfig('is_push_bear')) {
+//            return Response::json(['status' => 'fail', 'message' => '推送失败:请先启用并配置PushBear']);
+//        }
+//
+//        Notification::send(PushBearChannel::class, new Custom($title, $content));
 
-        Notification::send(PushBearChannel::class, new Custom($title, $content));
-
-        return Response::json(['status' => 'success', 'message' => '推送成功']);
+        return Response::json(['status' => 'fail', 'message' => '功能待开发']);
     }
 }

+ 12 - 2
app/Http/Controllers/Admin/SystemController.php

@@ -3,6 +3,9 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Channels\BarkChannel;
+use App\Channels\DingTalkChannel;
+use App\Channels\iYuuChannel;
+use App\Channels\PushDeerChannel;
 use App\Channels\PushPlusChannel;
 use App\Channels\ServerChanChannel;
 use App\Channels\TgChatChannel;
@@ -155,8 +158,6 @@ class SystemController extends Controller
                 'is_captcha',
                 'min_rand_traffic',
                 'max_rand_traffic',
-                'push_bear_send_key',
-                'push_bear_qrcode',
                 'forbid_mode',
                 'website_security_code',
             ];
@@ -208,6 +209,15 @@ class SystemController extends Controller
             case 'pushPlus':
                 Notification::sendNow(Auth::getUser(), new Custom($data[0], $data[1]), [PushPlusChannel::class]);
                 break;
+            case 'iYuu':
+                Notification::sendNow(Auth::getUser(), new Custom($data[0], $data[1]), [iYuuChannel::class]);
+                break;
+            case 'pushDeer':
+                Notification::sendNow(Auth::getUser(), new Custom($data[0], $data[1]), [PushDeerChannel::class]);
+                break;
+            case 'dingTalk':
+                Notification::sendNow(Auth::getUser(), new Custom($data[0], $data[1]), [DingTalkChannel::class]);
+                break;
             default:
                 return Response::json(['status' => 'fail', 'message' => '未知渠道']);
         }

+ 4 - 3
app/Notifications/PaymentConfirm.php

@@ -53,8 +53,8 @@ class PaymentConfirm extends Notification
         $goods = $this->order->goods;
 
         return [
-            'title'  => '🛒 人工支付',
-            'body'   => [
+            'title'    => '🛒 人工支付',
+            'body'     => [
                 [
                     'keyname' => 'ℹ️ 账号',
                     'value'   => $order->user->username,
@@ -68,7 +68,8 @@ class PaymentConfirm extends Notification
                     'value'   => $goods->name ?? '余额充值',
                 ],
             ],
-            'button' => [
+            'markdown' => '- ℹ️ 账号: '.$order->user->username.PHP_EOL.'- 💰 金额: '.sprintf('%1.2f', $order->amount).PHP_EOL.'- 📦 商品: '.($goods->name ?? '余额充值'),
+            'button'   => [
                 route('payment.notify', ['method' => 'manual', 'sign' => $this->sign, 'status' => 0]),
                 route('payment.notify', ['method' => 'manual', 'sign' => $this->sign, 'status' => 1]),
             ],

+ 6 - 0
app/Providers/SettingServiceProvider.php

@@ -3,6 +3,9 @@
 namespace App\Providers;
 
 use App\Channels\BarkChannel;
+use App\Channels\DingTalkChannel;
+use App\Channels\iYuuChannel;
+use App\Channels\PushDeerChannel;
 use App\Channels\PushPlusChannel;
 use App\Channels\ServerChanChannel;
 use App\Channels\TgChatChannel;
@@ -78,6 +81,9 @@ class SettingServiceProvider extends ServiceProvider
                 'serverChan' => ServerChanChannel::class,
                 'tgChat'     => TgChatChannel::class,
                 'weChat'     => WeChatChannel::class,
+                'iYuu'       => iYuuChannel::class,
+                'pushDear'   => PushDeerChannel::class,
+                'dingTalk'   => DingTalkChannel::class,
             ] as $key => $channel
         ) {
             $index = array_search($key, $channels, true);

+ 2 - 2
app/helpers.php

@@ -16,7 +16,7 @@ const Mbps = 125000;
 if (! function_exists('base64url_encode')) {
     function base64url_encode($data): string
     {
-        return strtr(base64_encode($data), ['+' => '-', '/' => '_', '=' => '']);
+        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
     }
 }
 
@@ -24,7 +24,7 @@ if (! function_exists('base64url_encode')) {
 if (! function_exists('base64url_decode')) {
     function base64url_decode($data)
     {
-        return base64_decode(strtr($data, '-_', '+/'));
+        return base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
     }
 }
 

+ 6 - 10
composer.lock

@@ -1400,16 +1400,16 @@
         },
         {
             "name": "geoip2/geoip2",
-            "version": "v2.12.2",
+            "version": "v2.13.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/maxmind/GeoIP2-php.git",
-                "reference": "83adb44ac4b9553d36b579a14673ed124583082f"
+                "url": "[email protected]:maxmind/GeoIP2-php.git",
+                "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/83adb44ac4b9553d36b579a14673ed124583082f",
-                "reference": "83adb44ac4b9553d36b579a14673ed124583082f",
+                "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
+                "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1456,11 +1456,7 @@
                 "geolocation",
                 "maxmind"
             ],
-            "support": {
-                "issues": "https://github.com/maxmind/GeoIP2-php/issues",
-                "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.12.2"
-            },
-            "time": "2021-11-30T18:15:25+00:00"
+            "time": "2022-08-05T20:32:58+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",

+ 12 - 9
config/common.php

@@ -52,21 +52,24 @@ return [
     ],
 
     'network_status' => [
-        1 => '✔️ 正常',
+        1 => '✔️正 常',
         2 => '🛑 海外阻断',
         3 => '🛑 国内阻断',
-        4 => '❌ 断连',
+        4 => '❌ 断 连',
     ],
 
     'notification' => [
         'labels' => [
-            1 => '邮件',
-            2 => 'ServerChan',
-            3 => 'Bark',
-            4 => 'Telegram',
-            5 => '微信企业',
-            6 => 'TG酱',
-            7 => 'PushPlus',
+            1  => '邮件',
+            2  => 'ServerChan',
+            3  => 'Bark',
+            4  => 'Telegram',
+            5  => '微信企业',
+            6  => 'TG酱',
+            7  => 'PushPlus',
+            8  => '爱语飞飞',
+            9  => 'PushDear',
+            10 => '钉钉',
         ],
     ],
 ];

+ 1 - 1
config/version.php

@@ -2,5 +2,5 @@
 
 return [
     'name' => 'ProxyPanel',
-    'number' => '2.7.0',
+    'number' => '2.7.x',
 ];

+ 3 - 3
database/migrations/2021_01_15_065207_create_notifications_table.php

@@ -47,7 +47,7 @@ class CreateNotificationsTable extends Migration
         foreach ($this->configs as $config) {
             \App\Models\Config::insert(['name' => $config]);
         }
-        \App\Models\Config::whereIn('name', $this->dropConfigs)->delete();
+        \App\Models\Config::destroy($this->dropConfigs);
     }
 
     /**
@@ -63,8 +63,8 @@ class CreateNotificationsTable extends Migration
         });
 
         foreach ($this->dropConfigs as $config) {
-            \App\Models\Config::insert(['name' => $config]);
+            \App\Models\Config::insertOrIgnore(['name' => $config]);
         }
-        \App\Models\Config::whereIn('name', $this->configs)->delete();
+        \App\Models\Config::destroy($this->configs);
     }
 }

+ 37 - 0
database/migrations/2022_08_04_001832_add_more_notifications.php

@@ -0,0 +1,37 @@
+<?php
+
+use App\Models\Config;
+use Illuminate\Database\Migrations\Migration;
+
+class AddMoreNotifications extends Migration
+{
+    protected $addConfigs = [
+        'iYuu_token',
+        'pushDeer_key',
+        'dingTalk_access_token',
+        'dingTalk_secret',
+    ];
+
+    protected $removeConfigs = [
+        'push_bear_send_key',
+        'push_bear_qrcode',
+    ];
+
+    public function up()
+    {
+        foreach ($this->addConfigs as $config) {
+            Config::insertOrIgnore(['name' => $config]);
+        }
+
+        Config::destroy($this->removeConfigs);
+    }
+
+    public function down()
+    {
+        foreach ($this->removeConfigs as $config) {
+            Config::insertOrIgnore(['name' => $config]);
+        }
+
+        Config::destroy($this->addConfigs);
+    }
+}

+ 0 - 3
database/seeds/PresetSeeder.php

@@ -78,9 +78,6 @@ class PresetSeeder extends Seeder
             'website_customer_service',
             'register_ip_limit',
             'is_email_filtering',
-            'is_push_bear',
-            'push_bear_send_key',
-            'push_bear_qrcode',
             'is_ban_status',
             'is_namesilo',
             'namesilo_key',

+ 26 - 23
resources/views/admin/config/system.blade.php

@@ -153,13 +153,23 @@
                             <x-system.input-limit title="提现限制" code="referral_money" :value="$referral_money" unit="元" help="满多少元才可以申请提现"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="notify">
-                            <x-system.input-test title="SCKEY" :value="$server_chan_key" code="server_chan_key" help='启用ServerChan,请务必填入本值(<a href=https://sc.ftqq.com
-                                    target=_blank>申请 SCKEY</a>)' holder="请到ServerChan申请" test="serverChan"/>
-                            <x-system.input-test title="Bark设备号" :value="$bark_key" code="bark_key" holder="安装并打开Bark后取得" type="url"
-                                                 help="推送消息到iOS设备,需要在iOS设备里装一个名为Bark的应用,取网址后的一长串代码,启用Bark,请务必填入本值" test="bark"/>
-                            <x-system.input-test title="Telegram Token" :value="$telegram_token" code="telegram_token" help="找 <a href=https://t.me/BotFather
-                                    target=_blank>@BotFather</a> 申请机器人" test="telegram"/>
-                            <x-system.input title="微信企业ID" :value="$wechat_cid" code="wechat_cid"
+                            <x-system.input-test title="ServerChan SCKEY" :value="$server_chan_key" code="server_chan_key" help='启用ServerChan,请务必填入本值(<a href=https://sc.ftqq.com
+                                    target=_blank>申请 SCKEY</a>)' holder="填入ServerChan的SCKEY -> 再点击更新" test="serverChan"/>
+                            <x-system.input-test title="PushDeer Key" :value="$pushDeer_key" code="pushDeer_key" help='启用PushDeer,请务必填入本值(<a href=http://www.pushdeer.com/official.html
+                                    target=_blank>申请 Push Key</a>)' holder="填入PushDeer的Push Key -> 再点击更新" test="pushDeer"/>
+                            <x-system.input-test title="IYUU令牌" :value="$iYuu_token" code="iYuu_token" help='启用爱语飞飞,请务必填入本值(<a href=http://iyuu.cn
+                                    target=_blank>申请 IYUU令牌</a>)' holder="填入爱语飞飞的IYUU令牌 -> 再点击更新" test="iYuu"/>
+                            <x-system.input-test title="Bark设备号" :value="$bark_key" code="bark_key" holder="填入Bark的设备号 -> 再点击更新"
+                                                 help="推送消息到iOS设备,需要在iOS设备里装一个名为Bark的应用,取网址后的一长串字符串,启用Bark,请务必填入本值" test="bark"/>
+                            <x-system.input-test title="Telegram" :value="$telegram_token" code="telegram_token" holder="填入Telegram的 Token -> 再点击更新" help="找 <a href=https://t
+                            .me/BotFather
+                                    target=_blank>@BotFather</a> 申请机器人获取TOKEN" test="telegram"/>
+                            <x-system.input-test title="PushPlus Token" :value="$pushplus_token" code="pushplus_token" help='启用PushPlus,请务必填入本值(<a href=https://www.pushplus.plus/push1.html
+                                    target=_blank>申请 Token</a>)' holder="请到ServerChan申请" test="pushPlus"/>
+                            <x-system.input title="钉钉自定义机器人 Access Token" :value="$dingTalk_access_token" code="dingTalk_access_token" holder="自定义机器人的WebHook中的access_token"
+                                            help="可以阅读<a href=https://open.dingtalk.com/document/group/custom-robot-access#title-jfe-yo9-jl2 target=_blank>钉钉手册</a>查阅步骤"/>
+                            <x-system.input-test title="钉钉自定义机器人 密钥" :value="$dingTalk_secret" code="dingTalk_secret" help='可选填!开启机器人[加签]就是必填项目!' holder="自定义机器人加签后出现的的密钥" test="dingTalk"/>
+                            <x-system.input title="微信企业ID" :value="$wechat_cid" code="wechat_cid" holder="填入微信企业ID -> 再点击更新"
                                             help="获取<a href=https://work.weixin.qq.com/wework_admin/frame#profile target=_blank>我的企业</a>中的企业ID"/>
                             <x-system.input title="微信企业应用ID" :value="$wechat_aid" code="wechat_aid" holder="应用的AgentId"
                                             help="在<a href=https://work.weixin.qq.com/wework_admin/frame#apps arget=_blank>应用管理</a>自建中创建应用 - AgentId"/>
@@ -168,39 +178,32 @@
                             <x-system.input title="微信企业应用EncodingAESKey" :value="$wechat_encodingAESKey" code="wechat_encodingAESKey" help='应用管理->应用->设置API接收->EncodingAESKey'/>
                             <x-system.input-test title="TG酱Token" :value="$tg_chat_token" code="tg_chat_token" help='启用TG酱,请务必填入本值(<a href=https://t.me/realtgchat_bot
                                     target=_blank>申请 Token</a>)' holder="请到Telegram申请" test="tgChat"/>
-                            <x-system.input-test title="PushPlus Token" :value="$pushplus_token" code="pushplus_token" help='启用PushPlus,请务必填入本值(<a href=https://www.pushplus.plus/push1.html
-                                    target=_blank>申请 Token</a>)' holder="请到ServerChan申请" test="pushPlus"/>
-                            <x-system.switch title="PushBear" code="is_push_bear" :check="$is_push_bear"
-                                             help='使用PushBear推送微信消息给用户(<a href="https://pushbear.ftqq.com/admin/#/signin" target="_blank">创建消息通道</a>)'/>
-                            <x-system.input title="PushBear SendKey" :value="$push_bear_send_key" code="push_bear_send_key" help="启用PushBear,请务必填入本值" holder="创建消息通道后即可获取"/>
-                            <x-system.input title="PushBear订阅二维码" :value="$push_bear_qrcode" code="push_bear_qrcode" help="创建消息通道后,在二维码上点击右键“复制图片地址”并粘贴至此处"
-                                            holder="填入消息通道的二维码URL" type="url"/>
                             <hr class="col-10"/>
                             <x-system.select title="账号过期通知" code="account_expire_notification" help="通知用户账号即将到期" multiple="1" :list="['邮箱' => 'mail', '站内通知' => 'database']"/>
                             <x-system.input-limit title="过期警告阈值" code="expire_days" :value="$expire_days" unit="元" help="【账号过期通知】开始阈值,每日通知用户"/>
                             <x-system.select title="流量耗尽通知" code="data_exhaust_notification" help="通知用户流量即将耗尽" multiple="1" :list="['邮箱' => 'mail', '站内通知' => 'database']"/>
                             <x-system.input-limit title="流量警告阈值" code="traffic_warning_percent" :value="$traffic_warning_percent" unit="%" help="【流量耗尽通知】开始阈值,每日通知用户"/>
                             <x-system.select title="节点离线提醒" code="node_offline_notification" help="每10分钟检测节点离线并提醒管理员" multiple="1"
-                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
-                                             'tgChat', 'PushPlus' => 'pushPlus']"/>
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' =>
+                                             'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' => 'tgChat', 'PushPlus' => 'pushPlus']"/>
                             <x-system.input-limit title="离线提醒次数" code="offline_check_times" :value="$offline_check_times" unit="次" help="24小时内提醒n次后不再提醒"/>
                             <x-system.select title="节点阻断提醒" code="node_blocked_notification" help="每小时检测节点是否被阻断并提醒管理员" multiple="1"
-                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' => 'tgChat', 'PushPlus'
+                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' => 'tgChat', 'PushPlus'
                                              => 'pushPlus']"/>
                             <x-system.input-limit title="阻断检测提醒" code="detection_check_times" :value="$detection_check_times" max="12" unit="次"
                                                   help="提醒N次后自动下线节点,为0/留空时不限制,不超过12"/>
                             <x-system.select title="支付成功通知" code="payment_received_notification" help="用户支付订单后通知用户订单状态" multiple="1"
                                              :list="['邮箱' => 'mail', '站内通知' => 'database', 'Telegram' => 'telegram']"/>
                             <x-system.select title="人工支付确认通知" code="payment_confirm_notification" help="用户使用人工支付后通知管理员处理订单"
-                                             :list="['关闭' => '', 'Telegram' => 'telegram', '微信企业' => 'weChat']"/>
+                                             :list="['关闭' => '', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat']"/>
                             <x-system.select title="工单关闭通知" code="ticket_closed_notification" help="工单关闭通知用户" multiple="1"
-                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' =>
                                              'tgChat', 'PushPlus' => 'pushPlus']"/>
                             <x-system.select title="新工单通知" code="ticket_created_notification" help="新工单通知管理/用户,取决于谁创建了新工单" multiple="1"
-                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' =>
                                              'tgChat', 'PushPlus' => 'pushPlus']"/>
                             <x-system.select title="工单回复通知" code="ticket_replied_notification" help="工单回复通知对方" multiple="1"
-                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' =>
                                              'tgChat', 'PushPlus' => 'pushPlus']"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="auto">
@@ -210,14 +213,14 @@
                             <x-system.input-limit title="订阅请求阈值" code="subscribe_ban_times" :value="$subscribe_ban_times" help="24小时内订阅链接请求次数限制"/>
                             <x-system.switch title="异常自动封号" code="is_traffic_ban" :check="$is_traffic_ban" help='1小时内流量超过异常阈值则自动封号(仅禁用代理)'/>
                             <x-system.select title="流量异常通知" code="data_anomaly_notification" help="1小时内流量超过异常阈值通知超管" multiple="1"
-                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' =>
                                              'tgChat', 'PushPlus' => 'pushPlus']"/>
                             <x-system.input-limit title="流量异常阈值" code="traffic_ban_value" :value="$traffic_ban_value" min="1" unit="GB" help="1小时内超过该值,则触发自动封号"/>
                             <x-system.input-limit title="封号时长" code="traffic_ban_time" :value="$traffic_ban_time" unit="分钟" help="触发流量异常导致用户被封禁的时长,到期后自动解封"/>
                             <x-system.switch title="端口回收机制" code="auto_release_port" :check="$auto_release_port" help="被封禁/过期{{config('tasks.release_port')}}天的账号端口自动释放"/>
                             <x-system.switch title="过期自动封禁" code="is_ban_status" :check="$is_ban_status" help="(慎重)封禁整个账号会重置账号的所有数据且会导致用户无法登录,不开启状态下只封禁用户代理"/>
                             <x-system.select title="节点使用报告" code="node_daily_notification" help="报告各节点流量昨日消耗情况" multiple="1"
-                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram', '微信企业' => 'weChat', 'TG酱' =>
+                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'PushDeer' => 'pushDear', '爱语飞飞' => 'iYuu', 'Telegram' => 'telegram', '钉钉' => 'dingTalk', '微信企业' => 'weChat', 'TG酱' =>
                                              'tgChat', 'PushPlus' => 'pushPlus']"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="other">

+ 8 - 8
resources/views/admin/marketing/pushList.blade.php

@@ -10,7 +10,7 @@
                 <h3 class="panel-title">推送消息列表</h3>
                 @can('admin.marketing.add')
                     <div class="panel-actions">
-                        <button class="btn btn-primary" data-toggle="modal" data-target="#send_modal"><i class="icon wb-plus"></i>推送消息</button>
+                        <button type="button" class="btn btn-primary disabled" data-toggle="modal" data-target="#send_modal"><i class="icon wb-plus"></i>推送消息</button>
                     </div>
                 @endcan
             </div>
@@ -29,11 +29,11 @@
                         <a href="{{route('admin.marketing.push')}}" class="btn btn-danger">{{trans('common.reset')}}</a>
                     </div>
                 </form>
-                <div class="alert alert-info alert-dismissible" role="alert">
-                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
-                        <span aria-hidden="true">×</span></button>
-                    仅会推送给关注了您的消息通道的用户 @can('admin.system.index')<a href="{{route('admin.system.index')}}" class="alert-link" target="_blank">设置PushBear</a> @else 设置PushBear @endcan
-                </div>
+{{--                <div class="alert alert-info alert-dismissible" role="alert">--}}
+{{--                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">--}}
+{{--                        <span aria-hidden="true">×</span></button>--}}
+{{--                    仅会推送给关注了您的消息通道的用户 @can('admin.system.index')<a href="{{route('admin.system.index')}}" class="alert-link" target="_blank">设置PushBear</a> @else 设置PushBear @endcan--}}
+{{--                </div>--}}
                 <table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
                     <thead class="thead-default">
                     <tr>
@@ -78,7 +78,7 @@
         <!-- 推送消息 -->
         <div id="send_modal" class="modal fade" tabindex="-1" data-focus-on="input:first" data-backdrop="static"
              data-keyboard="false">
-            <div class="modal-dialog modal-lg  modal-center">
+            <div class="modal-dialog modal-lg modal-center">
                 <div class="modal-content">
                     <div class="modal-header">
                         <button type="button" class="close" data-dismiss="modal" aria-label="Close">
@@ -111,7 +111,7 @@
                     </div>
                     <div class="modal-footer">
                         <button class="btn btn-danger mr-auto" data-dismiss="modal">取消</button>
-                        <button class="btn btn-primary" onclick="return send();">推送</button>
+                        <button type="button" class="btn btn-primary disabled" onclick="return send();">推送</button>
                     </div>
                 </div>
             </div>

+ 20 - 31
resources/views/user/index.blade.php

@@ -37,11 +37,11 @@
                                 <i class="wb-close red-400 font-size-40 mr-10"></i>
                                 <span class="font-size-40 font-weight-100">{{trans('user.status.expired')}}</span>
                                 <p class="font-weight-300 m-0 red-500">{{trans('user.account.reason.expired')}}</p>
-                            @elseif($unusedTraffic == 0)
+                            @elseif($unusedTraffic === '0B')
                                 <i class="wb-close red-400 font-size-40 mr-10"></i>
                                 <span class="font-size-40 font-weight-100">{{trans('user.status.disabled')}}</span>
                                 <p class="font-weight-300 m-0 red-500">{{trans('user.account.reason.traffic_exhausted')}}</p>
-                            @elseif(Auth::user()->isTrafficWarning() || $banedTime)
+                            @elseif($banedTime || Auth::user()->isTrafficWarning())
                                 <i class="wb-alert orange-400 font-size-40 mr-10"></i>
                                 <span class="font-size-40 font-weight-100">{{trans('user.status.limited')}}</span>
                                 <p class="font-weight-300 m-0 orange-500">{!!trans('user.account.reason.overused', ['data'=>sysConfig('traffic_ban_value')])!!}</p>
@@ -146,13 +146,13 @@
                                                 <div class="col">
                                                     <select class="form-control" id="subType" name="subType" data-plugin="selectpicker" data-style="btn-outline btn-primary">
                                                         <option value="" hidden>{{trans('common.all')}}</option>
-                                                        @if(in_array('ss',$subType))
+                                                        @if(in_array('ss', $subType, true))
                                                             <option value="1">{{trans('user.subscribe.ss_only')}}</option>
                                                         @endif
-                                                        @if(in_array('v2',$subType))
+                                                        @if(in_array('v2', $subType, true))
                                                             <option value="2">{{trans('user.subscribe.v2ray_only')}}</option>
                                                         @endif
-                                                        @if(in_array('trojan',$subType))
+                                                        @if(in_array('trojan', $subType, true))
                                                             <option value="3">{{trans('user.subscribe.trojan_only')}}</option>
                                                         @endif
                                                     </select>
@@ -200,17 +200,6 @@
                             </div>
                         </div>
                     </div>
-                    @if(sysConfig('is_push_bear') && sysConfig('push_bear_qrcode'))
-                        <div class="col-xl-4 mb-30">
-                            <div class="card card-shadow text-center h-full">
-                                <div class="card-block">
-                                    <h4 class="card-title"><i class="wb-bell mr-10 yellow-600"></i>{{trans('user.home.wechat_push')}}
-                                    </h4>
-                                    <div id="qrcode" class="mb-10"></div>
-                                </div>
-                            </div>
-                        </div>
-                    @endif
                 </div>
                 <div class="row" data-plugin="matchHeight" data-by-row="true">
                     <div class="col-xxl-6 mb-30">
@@ -285,22 +274,22 @@
     <script src="/assets/global/js/Plugin/aspieprogress.js"></script>
     <script src="/assets/global/js/Plugin/matchheight.js"></script>
     <script src="/assets/global/js/Plugin/bootstrap-select.js"></script>
-    @if(sysConfig('is_push_bear') && sysConfig('push_bear_qrcode'))
-        <script src="/assets/custom/easy.qrcode.min.js"></script>
-        <script>
-            // Options
-            const options = {
-                text: @json(sysConfig('push_bear_qrcode')),
-                width: 150,
-                height: 150,
-                backgroundImage: '{{asset('/assets/images/wechat.png')}}',
-                autoColor: true,
-            };
+    {{--    @if(sysConfig('is_push_bear') && sysConfig('push_bear_qrcode'))--}}
+    {{--        <script src="/assets/custom/easy.qrcode.min.js"></script>--}}
+    {{--        <script>--}}
+    {{--            // Options--}}
+    {{--            const options = {--}}
+    {{--                text: @json(sysConfig('push_bear_qrcode')),--}}
+    {{--                width: 150,--}}
+    {{--                height: 150,--}}
+    {{--                backgroundImage: '{{asset('/assets/images/wechat.png')}}',--}}
+    {{--                autoColor: true,--}}
+    {{--            };--}}
 
-            // Create QRCode Object
-            new QRCode(document.getElementById('qrcode'), options);
-        </script>
-    @endif
+    {{--            // Create QRCode Object--}}
+    {{--            new QRCode(document.getElementById('qrcode'), options);--}}
+    {{--        </script>--}}
+    {{--    @endif--}}
     <script>
         // 更换订阅地址
         function exchangeSubscribe() {