From 296ff40ea02a1ca0a303dd6f9c28d4d6e5229cbc Mon Sep 17 00:00:00 2001 From: hellcat <> Date: Sat, 19 Apr 2025 18:25:34 +0800 Subject: [PATCH] no message --- public/index.php | 10 + public/tests/hook.php | 28 +- src/Controllers/TestController.php | 2 +- src/Controllers/TomApi/Tg/HookController.php | 952 ++---------------- .../TomApi/Tg/HookController_back.php | 924 +++++++++++++++++ src/Services/Tg/Hook/Mod/Article_.php | 142 +++ src/Services/Tg/Hook/Mod/Base.php | 43 + src/Services/Tg/Hook/Mod/Cmd.php | 47 + src/Services/Tg/Hook/Mod/Duck.php | 144 +++ src/Services/Tg/Hook/Mod/Node.php | 202 ++++ src/Services/Tg/Hook/Mod/Order.php | 79 ++ src/Services/Tg/Hook/Mod/SaleCode.php | 51 + src/Services/Tg/Hook/Mod/Test.php | 21 + src/Services/Tg/Hook/Mod/Tk.php | 101 ++ src/Services/Tg/Hook/Mod/User.php | 75 ++ src/Services/Tg/Hook/Mod/Zf.php | 150 +++ src/Services/Tg/Http.php | 30 + src/Services/TomTool/Http.php | 11 +- 18 files changed, 2136 insertions(+), 876 deletions(-) create mode 100755 src/Controllers/TomApi/Tg/HookController_back.php create mode 100644 src/Services/Tg/Hook/Mod/Article_.php create mode 100644 src/Services/Tg/Hook/Mod/Base.php create mode 100644 src/Services/Tg/Hook/Mod/Cmd.php create mode 100644 src/Services/Tg/Hook/Mod/Duck.php create mode 100644 src/Services/Tg/Hook/Mod/Node.php create mode 100644 src/Services/Tg/Hook/Mod/Order.php create mode 100644 src/Services/Tg/Hook/Mod/SaleCode.php create mode 100644 src/Services/Tg/Hook/Mod/Test.php create mode 100644 src/Services/Tg/Hook/Mod/Tk.php create mode 100644 src/Services/Tg/Hook/Mod/User.php create mode 100644 src/Services/Tg/Hook/Mod/Zf.php create mode 100644 src/Services/Tg/Http.php diff --git a/public/index.php b/public/index.php index 7ffb10f0..484b59f1 100755 --- a/public/index.php +++ b/public/index.php @@ -21,6 +21,16 @@ use GuzzleHttp\Psr7\ServerRequest; use Slim\Factory\AppFactory; use Slim\Http\Factory\DecoratedResponseFactory; +function tomd($d, $type = 0) +{ + echo "
";
+    var_dump($d);
+    
+    if ($type) {
+        exit;
+    }
+}
+
 Boot::setTime();
 Boot::bootSentry();
 Boot::bootDb();
diff --git a/public/tests/hook.php b/public/tests/hook.php
index bf28a14d..9e1b52df 100644
--- a/public/tests/hook.php
+++ b/public/tests/hook.php
@@ -35,10 +35,36 @@ $oHttp->aData = [
             'type' => 'private'
         ],
         'date' => 1610000000,
-        "text" => "\/ry 你好,网站是正常运行的。用不了一般是没配置对,调试调试。",
+        "text" => "\/tk#find 2",
     ]
 ];
 
+$oHttp->aData['message']['text'] = '\/tk#find 1';
+$oHttp->aData['message']['text'] = '\/node#like__id 1';
+$oHttp->aData['message']['text'] = '\/node#set__12__name jjjjjkkkk';
+$oHttp->aData['message']['text'] = '\/zf#list';
+$oHttp->aData['message']['text'] = '\/duck#list';
+$oHttp->aData['message']['text'] = '\/zf#reset__youshi 2028-01-01';
+$oHttp->aData['message']['text'] = '\/zf#set__youshi__use_width 3#tb';
+$oHttp->aData['message']['text'] = '\/duck#set__us01__use_width 1#tb';
+$oHttp->aData['message']['text'] = '\/zf#del haha';
+$oHttp->aData['message']['text'] = '\/node#del 25';
+$oHttp->aData['message']['text'] = '\/duck#del hk02';
+$oHttp->aData['message']['text'] = '\/zf#add hk0222';
+$oHttp->aData['message']['text'] = '\/duck#find hk01';
+$oHttp->aData['message']['text'] = '\/duck#add uuu';
+$oHttp->aData['message']['text'] = '\/node#list';
+$oHttp->aData['message']['text'] = '\/order#groupBySaleCode 365'; // 默认1=24小时
+$oHttp->aData['message']['text'] = '\/user#report__day__300';
+$oHttp->aData['message']['text'] = '\/user#report__date__2025-01-01';
+$oHttp->aData['message']['text'] = '\/user#report__date__2022-01-01__2029-01-01';
+$oHttp->aData['message']['text'] = '\/node#clone 24';
+$oHttp->aData['message']['text'] = '\/tk#ry__1 ajsdklfjalksjdlkf';
+$oHttp->aData['message']['text'] = '\/tk#find 1';
+$oHttp->aData['message']['text'] = '\/user#find 1';
+
+$oHttp->aData['message']['text'] = '\/cmd#list';
+
 //{
 //    "update_id": 761180998,
 //    "message": {
diff --git a/src/Controllers/TestController.php b/src/Controllers/TestController.php
index bb786f94..d15516f3 100755
--- a/src/Controllers/TestController.php
+++ b/src/Controllers/TestController.php
@@ -29,7 +29,7 @@ final class TestController extends BaseController
     {
         $jobs = new CronService();
         
-        $jobs->mergeBandWidth();
+        $jobs->userCount();
         
 //        $jobs->reportBandWidth();
         
diff --git a/src/Controllers/TomApi/Tg/HookController.php b/src/Controllers/TomApi/Tg/HookController.php
index c9515cbb..125b3ae5 100755
--- a/src/Controllers/TomApi/Tg/HookController.php
+++ b/src/Controllers/TomApi/Tg/HookController.php
@@ -20,905 +20,115 @@ use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 use App\Utils\Tools;
 
-use App\Services\TomTool\Http;
+use App\Services\TomTool\Http as Http;
+use App\Services\Tg\Http as TGHttp;
 
 final class HookController
 {
     
-    public $sApiToken;
-    public $sApiChatId;
+    public function __construct()
+    {
+        
+    }
+
     
     public function cmd()
     {
-        $oTgStep = new TgStep();
         
-        $this->sApiToken = Config::obtain('telegram_token');
-        $this->sApiChatId = Config::obtain('telegram_chatid');
-        
-        $sUpdate = file_get_contents("php://input");
-        
-        $aUpdate = json_decode($sUpdate, true);
-        
-        @file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
-        
-        $aData['chatId'] = $aUpdate["message"]["chat"]["id"];
-        $aData['fromId'] = $aUpdate["message"]["from"]["id"];
-        
-        if (!isset($aUpdate["message"]["text"])) {
-            http_response_code(200);
-            echo "not have text";
-            exit;
-        }
-        
-        $sText = $aUpdate["message"]["text"];
-        
-        // 先检查step
-        if (strpos($sText, "/s ") === 0 && $oTgStep->fromIdHit($aData['fromId'])) {
+        try {
             
-            $sText = ltrim($sText, '/s');
-            $sText = trim($sText);
+            $oTGHttp = new TGHttp();
+//            $oTGHttp->sApiToken = env('telegram_token');
+//            $oTGHttp->sApiChatId = env('telegram_chatid');
             
-            $aTgStepFirst = $oTgStep->find($aData["fromId"]);
+            $sUpdate = file_get_contents("php://input");
             
-            if ($aTgStepFirst["cmd"] == "reply") {
+            $aUpdate = json_decode($sUpdate, true);
+            
+            @file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
+            
+            $aData['chatId'] = $aUpdate["message"]["chat"]["id"];
+            $aData['fromId'] = $aUpdate["message"]["from"]["id"];
+            
+            if (!isset($aUpdate["message"]["text"])) {
+                throw new \Exception("?");
+            }
+            
+            $sText = $aUpdate["message"]["text"];
+            
+            // test
+//            $sText = "\\//Article#List ni__aaa__bbb 111 222";
+//            $sText = "///\\\SaleCode#SetRate__zzxx 2";
+//            $sText = "///\\\SaleCode#List";
+//            $sText = "///\\\SaleCode#Find zzxx";
+//            $sText = "/Article#Like__sale_code zzx";
+//            $sText = "////Article#Add jxxjjjj";
+//            $sText = "//\\\//Article#Del 9";
+//            $sText = "/Article#Set__1__user_name xxx";
+            
+            @$aArg = explode(" ", $sText);
+            @$aOption = explode("__", $aArg[0]);
+            
+            $sCmd = $this->cleanCmd($aOption[0]);
+            
+            list($sClass, $sFunc) = explode("#", $sCmd);
+            $sClass = ucfirst($sClass);
+            $sFunc = ucfirst($sFunc);
+            
+            unset($aOption[0]);
+            unset($aArg[0]);
+            
+            $aParams['aOption'] = $aOption;
+            $aParams['aArg'] = $aArg;
+            $aParams['aUpdate'] = $aUpdate;
+            $aParams['aOther'] = [
+                'chatId'    => $aData['chatId'],
+                'fromId'    => $aData['fromId']
+            ];
+            
+            $sClassPath = "App\\Services\\Tg\\Hook\\Mod\\".$sClass;
+            
+//            tomd($sFunc);
+//            tomd($sClassPath, 1);
+
+            if (method_exists($sClassPath, $sFunc)) {
+                $oInstans = new $sClassPath();
+                $r = $oInstans->$sFunc($aParams);
                 
-                if ($aTgStepFirst['step'] == 1) {
-                    $oHttp = new Http();
-                    
-                    $oHttp->sMethod = "put";
-                    $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/ticket/".$aTgStepFirst['cache']['ticketId'];
-                    $oHttp->bIsJson = true;
-                    $aData['comment'] = $sText;
-                    $aData['admin_name'] = $aUpdate["message"]["from"]["first_name"];
-                    $oHttp->aData = $aData;
-                    
-                    $r = @json_decode($oHttp->send(), true);
-                    
-                    // 不论失败成功都清除step
-                    $oTgStep->clearByFromId($aUpdate["message"]["from"]["id"]);
-                    
-                    if ($r["ret"] == 1) {
-                        $sMessage = "成功";
+                // 可以不返回,里面直接send
+                if (isset($r)) {
+                    if (empty($r)) { $r = 'hook的mod返回空'; }
+                    // 返回可以是数组
+                    if (is_array($r)) {
+                        foreach ($r as $row) {
+                            $oTGHttp->sendToTG($row);
+                        }
                     } else {
-                        $sMessage = "失败";
-                        Http::response(500, json_encode($aData));
+                        $oTGHttp->sendToTG($r);
                     }
                     
-                    $this->sendMessage($sMessage);
-                    
                     Http::response(200, 'ok');
                 }
                 
-            }
-            
-        }
-        
-        // 打断
-        if ($sText === "/break") {
-            
-            $oTgStep->clearByFromId($aData["fromId"]);
-            
-            $this->sendMessage("ok");
-            
-            http_response_code(200);exit;
-        }
-        
-        // 命令列表
-        // /cmdList
-        if (strpos($sText, '/cmdList') === 0 || strpos($sText, '\/cmdList') === 0) {
-            
-            $aCmdList = [
-                '流量报告'  => 'reportWidth',
-                '查找用户'  => 'userFind 11',
-                '查找订单'  => 'orderFindByUser 11',
-                '回复工单'  => 'reply 11 + s 你好',
-                '快捷回单'  => 'ry 11 你好',
-                '工单查找'  => 'ticketFind 11',
-                '用户报表'  => 'reportUser_day_7 && reportUser_date_2025-02-02 && reportUser_date_2025-02-02_2025-03-03',
-                'duck添加&转发'  => 'duckAdd jp02',
-                'duck删除&转发'  => 'duckDel jp02',
-                'duck修改&转发'  => 'duckOption|max_width|jp01 1.66#tb',
-                'duck列表&转发'  => 'duckList',
-                'duck查找'  => 'duckFind jp02',
-                '转发重置'  => 'zhuanfaReset-youshi 2025-02-02',
-                'node修改'  => 'nodeOption#name#11 haha',
-                '节点like'  => 'nodeLike#duck jp02',
-                'node删除'  => 'nodeDel 18',
-                'node复制'  => 'nodeCopy 18',
-                '节点列表简洁'=> 'nodeList',
-            ];
-            
-            $this->sendMessage(json_encode($aCmdList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 流量报告
-        // /reportWidth
-        if (strpos($sText, '/reportWidth') === 0 || strpos($sText, '\/reportWidth') === 0) {
-            
-            $jobs = new \App\Services\Cron();
-            
-            $jobs->reportBandWidth();
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 查找用户
-        // /userFind 11
-        if (strpos($sText, '/userFind') === 0 || strpos($sText, '\/userFind') === 0) {
-            
-            list(, $iUserId) = explode(" ", $sText, 2);
-            
-            $oUser = User::find($iUserId);
-            
-            if ($oUser) {
-                $aUser = $oUser->toArray();
-                unset($aUser['pass']);
-                unset($aUser['passwd']);
-                unset($aUser['uuid']);
-                unset($aUser['method']);
-                unset($aUser['is_admin']);
-                unset($aUser['theme']);
-                unset($aUser['ga_token']);
-                unset($aUser['ga_enable']);
-                unset($aUser['api_token']);
-                unset($aUser['is_dark_mode']);
-                unset($aUser['locale']);
-                
-                $aUser['transfer_today'] = Tools::flowToGB($aUser['transfer_today']).'GB';
-                $aUser['transfer_total'] = Tools::flowToGB($aUser['transfer_total']).'GB';
-                $aUser['transfer_enable'] = Tools::flowToGB($aUser['transfer_enable']).'GB';
-                $aUser['last_use_time'] = date('Y-m-d H:i:s', $aUser['last_use_time']);
             } else {
-                $aUser = ["not have id" => $iUserId];
+                throw new \Exception("没有这个方法:".$sClass.'#'.$sFunc);
             }
 
-            $this->sendMessage(json_encode($aUser, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+        } catch (\Throwable $e) {
+            $sMessage = "错误(line:".$e->getLine()."): " . $e->getMessage();
             
-            Http::response(200, 'ok');
+            $oTGHttp->sendToTG($sMessage);
             
+            Http::response(200, 'error');
         }
-        
-        // 查找订单
-        // orderFindByUser 11
-        if (strpos($sText, '/orderFindByUser') === 0 || strpos($sText, '\/orderFindByUser') === 0) {
-            
-            list(, $iUserId) = explode(" ", $sText, 2);
-            
-            $aOrder = Order::where("user_id", $iUserId)->get()->toArray();
-            
-            if ($aOrder) {
-                $aOrderNew = [];
-                foreach ($aOrder as $k => $v) {
-                    $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
-                    $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
-                    $v['product_content'] = json_decode($v['product_content']);
-                    $aOrderNew[] = $v;
-                }
-            } else {
-                $aOrderNew = ["not have id" => $iUserId];
-            }
-            
-            $this->sendMessage(json_encode($aOrderNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 回复工单
-        // /reply 11 + /s 你好
-        if (strpos($sText, '/reply') === 0) {
-            
-            // 先清除一遍,只进行一个进程
-            $oTgStep->clearByFromId($aData["fromId"]);
-                 
-            $iTicketId = str_replace('/reply', '', $sText);
-            $iTicketId = (int) trim($iTicketId);
-            
-            $oTgStep->add($aData['fromId'], 'reply', 1, ["ticketId" => $iTicketId]);
-            
-            $sMessage = "将回复工单【".$iTicketId."】,请输入回复内容。";
-
-            $this->sendMessage($sMessage);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 快捷回复工单
-        // /ry 11 你好
-        if (strpos($sText, '/ry') === 0 || strpos($sText, '\/ry') === 0) {
-            
-            try {
-                $sText = $this->trimText($sText, '/ry');
-                
-                list($iTicketId, $sText) = explode(" ", $sText, 2);
-                
-                $oHttp = new Http();
-                
-                $oHttp->sMethod = "put";
-                $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/ticket/".$iTicketId;
-                $oHttp->bIsJson = true;
-                $aData['comment'] = $sText;
-                $aData['admin_name'] = $aUpdate["message"]["from"]["first_name"];
-                $oHttp->aData = $aData;
-                
-                $r = @json_decode($oHttp->send(), true);
-                
-                // 不论失败成功都清除 step
-                $oTgStep->clearByFromId($aUpdate["message"]["from"]["id"]);
-                
-                if ($r["ret"] == 1) {
-                    $sMessage = "成功";
-                } else {
-                    $sMessage = "失败";
-                    Http::response(200, json_encode($aData));
-                }
-                
-                $this->sendMessage($sMessage);
-                
-                Http::response(200, 'ok');
-                
-            } catch (Exception $e) {
-                
-                $sMessage = "发生错误: " . $e->getMessage();
-                
-                $this->sendMessage($sMessage);
-                
-                Http::response(200, '内部服务器错误');
-                
-            }
-            
-        }
-        
-        // 复制节点
-        // /nodeCopy 11
-        if (strpos($sText, '/nodeCopy') === 0 || strpos($sText, '\/nodeCopy') === 0) {
-            
-            list(, $iNodeId) = explode(" ", $sText, 2);
-            
-            $oHttp = new Http();
-            
-            $oHttp->sMethod = "post";
-            $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/node/".$iNodeId."/copy";
-            $oHttp->bIsJson = true;
-            $oHttp->aData = $aData;
-            
-            $r = @json_decode($oHttp->send(), true);
-            
-            if ($r["ret"] == 1) {
-                $sMessage = "成功";
-            } else {
-                $sMessage = "失败";
-                Http::response(500, json_encode($aData));
-            }
-            
-            $this->sendMessage($sMessage);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 用户报表
-        // /reportUser_day_7 && /reportUser_date_2025-02-02 && /reportUser_date_2025-02-02_2025-03-03
-        if (strpos($sText, '/reportUser') === 0 || strpos($sText, '\/reportUser') === 0) {
-            
-            @list(, $sOption1, $sOption2, $sOption3) = explode("_", $sText, 4);
-            
-            $sMsg = '?';
-            
-            if ($sOption1 == 'day') {
-                
-                $sMsg = (new ServiceTgReportUser())->ByDay($sOption2);
-                
-            }
-            
-            if ($sOption1 == 'date') {
-                $sMsg = (new ServiceTgReportUser())->ByDate($sOption2, $sOption3);
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 优惠卷报表
-        // /reportCoupon#7
-        if (strpos($sText, '/reportCoupon') === 0 || strpos($sText, '\/reportCoupon') === 0) {
-            try {
-                @list($sCmd, $iDay) = explode("#", $sText, 2);
-                
-                // 确保 $iDay 是一个有效的数字
-                if (!is_numeric($iDay) || $iDay < 0) {
-                    $this->sendMessage('无效的天数参数');
-                    Http::response(200, '内部服务器错误');
-                }
-
-                $sStartTime = strtotime("-$iDay days");
-
-                $aOrderList = Order::where('update_time', '>=', $sStartTime)
-                        ->whereIn('status', ['activated', 'pending_activation']) // 添加状态条件
-                        ->select('coupon',
-                                 \App\Services\DB::raw('count(*) as total'),
-                                 \App\Services\DB::raw('SUM(price) as total_price'))
-                        ->groupBy('coupon')
-                        ->get()
-                        ->toArray();
-
-                $sMsg = '从 '.date("Y-m-d H:i:s", $sStartTime);
-                foreach ($aOrderList as $row) {
-                    $coupon = str_replace('.', '#', $row['coupon']);
-                    if (!$coupon) {
-                        $coupon = '无';
-                    }
-                    $sMsg .= "\n\n";
-                    $sMsg .= $coupon . ' - ' . $row['total_price'] . ' / ' . $row['total'];
-                }
-
-                $this->sendMessage($sMsg);
-                
-                Http::response(200, 'ok');
-            } catch (Exception $e) {
-                // 处理异常
-                $errorMsg = '发生错误: ' . $e->getMessage();
-                $this->sendMessage($errorMsg);
-                
-                // 返回错误响应
-                Http::response(200, '内部服务器错误');
-            }
-        }
-
-
-        // 节点列表(简洁)
-        // /nodeList
-        if (strpos($sText, '/nodeList') === 0 || strpos($sText, '\/nodeList') === 0) {
-            
-            $aNodeList = Node::where('type', 1)->orderBy('name', 'asc')->get()->toArray();
-            
-            $sMsg = '';
-            foreach ($aNodeList as $row) {
-                $sMsg .= "\n\n";
-                $sMsg .= $row['name'].', id:'.$row['id'].', duck:'.$row['duck_code'].', zf:'.$row['zhuanfa_code'].', sort:'.$row['sort'];
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 添加duck
-        // /duckAdd jp01
-        if (strpos($sText, '/duckAdd') === 0 || strpos($sText, '\/duckAdd') === 0) {
-            
-            list($sCmd, $sCode) = explode(" ", $sText, 2);
-            
-            try {
-                $oDucks = new Ducks();
-                $oDucks->code = $sCode;
-
-                if ($oDucks->save()) {
-                    $sMsg = "成功";
-                } else {
-                    $sMsg = "失败";
-                }
-            } catch (\Exception $e) {
-                $sMsg = json_encode($e->getMessage());
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 查找duck
-        // /duckFind jp01
-        if (strpos($sText, '/duckFind') === 0 || strpos($sText, '\/duckFind') === 0) {
-            
-            list($sCmd, $sCode) = explode(" ", $sText, 2);
-            
-            $aData = Ducks::where('code', $sCode)->first()->toArray();
-            
-            $aData['use_width'] = Tools::flowToGB($aData['use_width']).'GB';
-            $aData['max_width'] = Tools::flowToGB($aData['max_width']).'GB';
-            $aData['today_width'] = Tools::flowToGB($aData['today_width']).'GB';
-            
-            $this->sendMessage(json_encode($aData, JSON_PRETTY_PRINT));
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 添加zhuanfa
-        // /zhuanfaAdd jp01
-        if (strpos($sText, '/zhuanfaAdd') === 0 || strpos($sText, '\/zhuanfaAdd') === 0) {
-            
-            list($sCmd, $sCode) = explode(" ", $sText, 2);
-            
-            try {
-                $oZhuanfas = new Zhuanfas();
-                $oZhuanfas->code = $sCode;
-
-                if ($oZhuanfas->save()) {
-                    $sMsg = "成功";
-                } else {
-                    $sMsg = "失败";
-                }
-            } catch (\Exception $e) {
-                $sMsg = json_encode($e->getMessage());
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 删除duck
-        // /duckDel jp01
-        if (strpos($sText, '/duckDel') === 0 || strpos($sText, '\/duckDel') === 0) {
-            
-            list($sCmd, $sCode) = explode(" ", $sText, 2);
-            
-            try {
-                $oDucks = Ducks::where("code", $sCode)->first();
-
-                if ($oDucks) {
-                    // 尝试删除记录
-                    $deleted = $oDucks->delete();
-
-                    if ($deleted) {
-                        // 删除成功
-                        $sMsg = "成功";
-                    } else {
-                        // 删除失败
-                        $sMsg = "失败";
-                    }
-                } else {
-                    // 找不到记录
-                    $sMsg = "找不到记录";
-                }
-            } catch (\Exception $e) {
-                // 捕获异常并返回错误信息
-                $sMsg = json_encode($e->getMessage());
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 删除node
-        // /duckDel jp01
-        if (strpos($sText, '/nodeDel') === 0 || strpos($sText, '\/nodeDel') === 0) {
-            
-            list($sCmd, $iId) = explode(" ", $sText, 2);
-            
-            $sMsg = '?';
-            
-            try {
-                $oNode = Node::where("id", $iId)->first();
-
-                if ($oNode) {
-                    // 尝试删除记录
-                    $deleted = $oNode->delete();
-
-                    if ($deleted) {
-                        // 删除成功
-                        $sMsg = "成功";
-                    } else {
-                        // 删除失败
-                        $sMsg = "失败";
-                    }
-                } else {
-                    // 找不到记录
-                    $sMsg = "找不到记录";
-                }
-            } catch (\Exception $e) {
-                // 捕获异常并返回错误信息
-                $sMsg = json_encode($e->getMessage());
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 删除zhuanfa
-        // /zhuanfaDel jp01
-        if (strpos($sText, '/zhuanfaDel') === 0 || strpos($sText, '\/zhuanfaDel') === 0) {
-            
-            list($sCmd, $sCode) = explode(" ", $sText, 2);
-            
-            try {
-                $oZhuanfas = Zhuanfas::where("code", $sCode)->first();
-
-                if ($oZhuanfas) {
-                    // 尝试删除记录
-                    $deleted = $oZhuanfas->delete();
-
-                    if ($deleted) {
-                        // 删除成功
-                        $sMsg = "成功";
-                    } else {
-                        // 删除失败
-                        $sMsg = "失败";
-                    }
-                } else {
-                    // 找不到记录
-                    $sMsg = "找不到记录";
-                }
-            } catch (\Exception $e) {
-                // 捕获异常并返回错误信息
-                $sMsg = json_encode($e->getMessage());
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 修改duck
-        // /duckOption@end_date@jp01 2025_02_02
-        // /duckOption@max_width@jp01 1.66#tb
-        if (strpos($sText, '/duckOption') === 0 || strpos($sText, '\/duckOption') === 0) {
-            
-            list($sCmd, $sSet) = explode(" ", $sText, 2);
-            list(, $sField, $sCode) = explode("#", $sCmd, 3);
-        
-            if ($sSet) {
-                @list($iWidth, $sWidthType) = explode("|", $sSet, 2);
-            } else {
-                $sMsg = "没有参数";
-            }
-            
-            
-            if ($sWidthType == 'tb') {
-                $sSet = Tools::tomTbToB($iWidth);
-            }
-            
-            if ($sWidthType == 'gb') {
-                $sSet = Tools::tomGbToB($iWidth);
-            }
-            
-            $sMsg = '?';
-            try {
-                
-                $oDuck = Ducks::where('code', $sCode)->first();
-                
-                if (!$oDuck) {
-                    $sMsg = "没有这个code";
-                } else {
-                    $oDuck->$sField = $sSet;
-                    if ($oDuck->save()) {
-                        $sMsg = "成功"; // 保存成功
-                    } else {
-                        $sMsg = "失败"; // 保存失败
-                    }
-                }
-                
-            } catch (\Illuminate\Database\QueryException $e) {
-                
-                $sMsg = json_encode($e->getMessage());
-                
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 修改zhuanfa
-        // /zhuanfaOption-end_date-jp01 2025_02_02
-        // /zhuanfaOption-max_width-jp01 1.66#tb
-        if (strpos($sText, '/zhuanfaOption') === 0 || strpos($sText, '\/zhuanfaOption') === 0) {
-            
-            list($sCmd, $sSet) = explode(" ", $sText, 2);
-            list(, $sField, $sCode) = explode("-", $sCmd, 3);
-            @list($iWidth, $sWidthType) = explode("#", $sSet, 2);
-            
-            if ($sWidthType == 'tb') {
-                $sSet = Tools::tomTbToB($iWidth);
-            }
-            
-            if ($sWidthType == 'gb') {
-                $sSet = Tools::tomGbToB($iWidth);
-            }
-            
-            $sMsg = '?';
-            try {
-                
-                $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
-                
-                if (!$oZhuanfas) {
-                    $sMsg = "没有这个code";
-                } else {
-                    $oZhuanfas->$sField = $sSet;
-                    if ($oZhuanfas->save()) {
-                        $sMsg = "成功"; // 保存成功
-                    } else {
-                        $sMsg = "失败"; // 保存失败
-                    }
-                }
-                
-            } catch (\Illuminate\Database\QueryException $e) {
-                
-                $sMsg = json_encode($e->getMessage());
-                
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 转发重置
-        // /zhuanfaReset-youshi 2025-02-02
-        if (strpos($sText, '/zhuanfaReset') === 0 || strpos($sText, '\/zhuanfaReset') === 0) {
-            
-            list($sCmd, $sDate) = explode(" ", $sText, 2);
-            list(, $sCode) = explode("-", $sCmd, 2);
-            
-            $sMsg = '?';
-            try {
-                
-                $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
-                
-                if (!$oZhuanfas) {
-                    $sMsg = "没有这个code";
-                } else {
-                    $oZhuanfas->use_width = 0;
-                    $oZhuanfas->end_date = $sDate;
-                    if ($oZhuanfas->save()) {
-                        $sMsg = "成功"; // 保存成功
-                    } else {
-                        $sMsg = "失败"; // 保存失败
-                    }
-                }
-                
-            } catch (\Illuminate\Database\QueryException $e) {
-                
-                $sMsg = json_encode($e->getMessage());
-                
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // duck list
-        // /duckList
-        if (strpos($sText, '/duckList') === 0 || strpos($sText, '\/duckList') === 0) {
-            
-            $aDuckList = Ducks::orderBy('code')->get()->toArray();
-            
-            $aMsgData = [];
-            foreach ($aDuckList as $k => $v) {
-                $v['use_width'] = Tools::flowToGB($v['use_width']).'g';
-                $v['max_width'] = Tools::flowToGB($v['max_width']).'g';
-                $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
-                $aMsgData[] = $v;
-            }
-            
-            $this->sendMessage(json_encode($aMsgData, JSON_PRETTY_PRINT));
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // zhuanfa list
-        // /zhuanfaList
-        if (strpos($sText, '/zhuanfaList') === 0 || strpos($sText, '\/zhuanfaList') === 0) {
-            
-            $aZhuanfaList = Zhuanfas::orderBy('code')->get()->toArray();
-            
-            $aMsgData = [];
-            foreach ($aZhuanfaList as $k => $v) {
-                $v['use_width'] = Tools::flowToTB($v['use_width'])."t";
-                $v['max_width'] = Tools::flowToTB($v['max_width']).'t';
-                $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
-                $aMsgData[] = $v;
-            }
-            
-            $this->sendMessage(json_encode($aMsgData, JSON_PRETTY_PRINT));
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 节点设置变更
-        // /nodeOption@name@1 haha
-        if (strpos($sText, '/nodeOption') === 0 || strpos($sText, '\/nodeOption') === 0) {
-            
-            list($sCmd, $sSet) = explode(" ", $sText, 2);
-            
-            list(, $sField, $iNodeId) = explode("#", $sCmd, 3);
-            
-            switch ($sField) {
-                case "config":
-                    $sField = "custom_config";
-                    break;
-                case "duck":
-                    $sField = "duck_code";
-                    break;
-                case "zhuanfa":
-                    $sField = "zhuanfa_code";
-                    break;
-                default:
-                    $sField = $sField;
-                    break;
-            }
-            
-            $sMsg = '?';
-            try {
-                
-                $oNode = Node::find($iNodeId);
-                
-                if (!$oNode) {
-                    $sMsg = "没有这个id";
-                } else {
-                    $oNode->$sField = $sSet;
-                    $oNode->save();
-                    
-                    $sMsg = "ok";
-                }
-                
-            } catch (\Illuminate\Database\QueryException $e) {
-                
-                $sMsg = "数据库操作失败";
-                
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        // 节点搜索
-        // /nodeLike_duck_type1 jp02
-        if (strpos($sText, '/nodeLike') === 0 || strpos($sText, '\/nodeLike') === 0) {
-                
-            @list($sCmd, $sLike) = explode(" ", $sText);
-            
-            @list(, $sField, $sMod) = explode("#", $sCmd, 3);
-            
-            switch ($sField) {
-                case "port":
-                    $sField = "custom_config";
-                    break;
-                case "config":
-                    $sField = "custom_config";
-                    break;
-                case "duck":
-                    $sField = "duck_code";
-                    break;
-                case "zhuanfa":
-                    $sField = "zhuanfa_code";
-                    break;
-                default:
-                    $sField = $sField;
-                    break;
-            }
-            
-            $sMsg = '?';
-        
-            try {
-                
-                $oNodeList = Node::where($sField, 'like', '%' . $sLike . '%');
-                
-                if ($sMod == 'type1') {
-                    $oNodeList->where('type', 1);
-                }
-                
-                $aNodeList = $oNodeList->orderBy('type', 'desc')->orderBy('name', 'asc')->get()->toArray();
-                
-            } catch (\Illuminate\Database\QueryException $e) {
-                
-                $sMsg = '字段不存在';
-                
-            }
-            
-            if (empty($aNodeList)) {
-                
-                $sMsg = "没有";
-                
-            } else {
-                
-                $aNodeListNew = [];
-                foreach ($aNodeList as $row) {
-                    
-                    $row['custom_config'] = json_decode($row['custom_config']);
-                    $row['dynamic_rate_config'] = json_decode($row['dynamic_rate_config']);
-                    $row['node_bandwidth_limit'] = Tools::flowToGB($row['node_bandwidth_limit']).'GB';
-                    $row['node_bandwidth'] = Tools::flowToGB($row['node_bandwidth']).'GB';
-                    $row['node_heartbeat'] = date('Y-m-d H:i:s', $row['node_heartbeat']);
-                    unset($row['is_dynamic_rate']);
-                    unset($row['dynamic_rate_type']);
-                    unset($row['dynamic_rate_config']);
-                    unset($row['bandwidthlimit_resetday']);
-                    unset($row['is_dynamic_rate']);
-                    unset($row['password']);
-                    
-//                    $aNodeListNew[] = $row;
-                    
-                    $sMsg = json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
-                    
-                    $this->sendMessage($sMsg);
-                }
-                
-//                $sMsg = json_encode($aNodeListNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
-                Http::response(200, 'ok');
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-       
-        // 工单查找
-        // /ticketFind 11
-        if (strpos($sText, '/ticketFind') === 0) {
-            
-            $iTicketId = $this->trimText($sText, '/ticketFind');
-            
-            $aTicket = Ticket::where("id", $iTicketId)->first()->toArray();
-            
-            $sMsg = "title:".$aTicket['title']."。\n";
-            
-            $aTicketContent = json_decode($aTicket['content'], true);
-            
-            if (!is_array($aTicketContent[0])) {
-                $aTicketContent[] = $aTicketContent;
-            }
-            
-            foreach ($aTicketContent as $row) {
-                $sMsg .= "\n";
-                $sMsg .= "name:".$row['commenter_name']."\n";
-                $sMsg .= "comment:".$row['comment']."\n";
-            }
-            
-            $this->sendMessage($sMsg);
-            
-            Http::response(200, 'ok');
-            
-        }
-        
-        Http::response(200, '无');
-
     }
     
-    private function trimText($sText, $sTrim)
-    {
-        $sText = ltrim($sText, $sTrim);
-        $sText = trim($sText);
+    private function cleanCmd($input) {
         
-        return $sText;
-    }
-    
-    private function sendMessage($sText = '?') {
-        
-        if ($_ENV['is_loc'] === true) {
-            echo "
";
-            var_dump($sText);
-        } else {
-            $url = "https://api.telegram.org/bot$this->sApiToken/sendMessage?chat_id=$this->sApiChatId&text=" . urlencode($sText);
-            file_get_contents($url);
-        }
+        $input = str_replace('\\', '', $input);
+        $input = str_replace('/', '', $input);
         
+        return $input;
     }
     
 }
diff --git a/src/Controllers/TomApi/Tg/HookController_back.php b/src/Controllers/TomApi/Tg/HookController_back.php
new file mode 100755
index 00000000..8841fb7c
--- /dev/null
+++ b/src/Controllers/TomApi/Tg/HookController_back.php
@@ -0,0 +1,924 @@
+sApiToken = Config::obtain('telegram_token');
+        $this->sApiChatId = Config::obtain('telegram_chatid');
+        
+        $sUpdate = file_get_contents("php://input");
+        
+        $aUpdate = json_decode($sUpdate, true);
+        
+        @file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
+        
+        $aData['chatId'] = $aUpdate["message"]["chat"]["id"];
+        $aData['fromId'] = $aUpdate["message"]["from"]["id"];
+        
+        if (!isset($aUpdate["message"]["text"])) {
+            http_response_code(200);
+            echo "not have text";
+            exit;
+        }
+        
+        $sText = $aUpdate["message"]["text"];
+        
+        // 先检查step
+        if (strpos($sText, "/s ") === 0 && $oTgStep->fromIdHit($aData['fromId'])) {
+            
+            $sText = ltrim($sText, '/s');
+            $sText = trim($sText);
+            
+            $aTgStepFirst = $oTgStep->find($aData["fromId"]);
+            
+            if ($aTgStepFirst["cmd"] == "reply") {
+                
+                if ($aTgStepFirst['step'] == 1) {
+                    $oHttp = new Http();
+                    
+                    $oHttp->sMethod = "put";
+                    $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/ticket/".$aTgStepFirst['cache']['ticketId'];
+                    $oHttp->bIsJson = true;
+                    $aData['comment'] = $sText;
+                    $aData['admin_name'] = $aUpdate["message"]["from"]["first_name"];
+                    $oHttp->aData = $aData;
+                    
+                    $r = @json_decode($oHttp->send(), true);
+                    
+                    // 不论失败成功都清除step
+                    $oTgStep->clearByFromId($aUpdate["message"]["from"]["id"]);
+                    
+                    if ($r["ret"] == 1) {
+                        $sMessage = "成功";
+                    } else {
+                        $sMessage = "失败";
+                        Http::response(500, json_encode($aData));
+                    }
+                    
+                    $this->sendMessage($sMessage);
+                    
+                    Http::response(200, 'ok');
+                }
+                
+            }
+            
+        }
+        
+        // 打断
+        if ($sText === "/break") {
+            
+            $oTgStep->clearByFromId($aData["fromId"]);
+            
+            $this->sendMessage("ok");
+            
+            http_response_code(200);exit;
+        }
+        
+        // 命令列表
+        // /cmdList
+        if (strpos($sText, '/cmdList') === 0 || strpos($sText, '\/cmdList') === 0) {
+            
+            $aCmdList = [
+                '流量报告'  => 'reportWidth',
+                '查找用户'  => 'userFind 11',
+                '查找订单'  => 'orderFindByUser 11',
+                '回复工单'  => 'reply 11 + s 你好',
+                '快捷回单'  => 'ry 11 你好',
+                '工单查找'  => 'ticketFind 11',
+                '用户报表'  => 'reportUser_day_7 && reportUser_date_2025-02-02 && reportUser_date_2025-02-02_2025-03-03',
+                'duck添加&转发'  => 'duckAdd jp02',
+                'duck删除&转发'  => 'duckDel jp02',
+                'duck修改&转发'  => 'duckOption|max_width|jp01 1.66#tb',
+                'duck列表&转发'  => 'duckList',
+                'duck查找'  => 'duckFind jp02',
+                '转发重置'  => 'zhuanfaReset-youshi 2025-02-02',
+                'node修改'  => 'nodeOption#name#11 haha',
+                '节点like'  => 'nodeLike#duck jp02',
+                'node删除'  => 'nodeDel 18',
+                'node复制'  => 'nodeCopy 18',
+                '节点列表简洁'=> 'nodeList',
+            ];
+            
+            $this->sendMessage(json_encode($aCmdList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+            
+            Http::response(200, 'ok');
+            
+        }
+        
+        // 流量报告
+        // /reportWidth
+        if (strpos($sText, '/reportWidth') === 0 || strpos($sText, '\/reportWidth') === 0) {
+            
+//            $jobs = new \App\Services\Cron();
+//            
+//            $jobs->reportBandWidth();
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 查找用户
+        // /userFind 11
+        if (strpos($sText, '/userFind') === 0 || strpos($sText, '\/userFind') === 0) {
+            
+//            list(, $iUserId) = explode(" ", $sText, 2);
+//            
+//            $oUser = User::find($iUserId);
+//            
+//            if ($oUser) {
+//                $aUser = $oUser->toArray();
+//                unset($aUser['pass']);
+//                unset($aUser['passwd']);
+//                unset($aUser['uuid']);
+//                unset($aUser['method']);
+//                unset($aUser['is_admin']);
+//                unset($aUser['theme']);
+//                unset($aUser['ga_token']);
+//                unset($aUser['ga_enable']);
+//                unset($aUser['api_token']);
+//                unset($aUser['is_dark_mode']);
+//                unset($aUser['locale']);
+//                
+//                $aUser['transfer_today'] = Tools::flowToGB($aUser['transfer_today']).'GB';
+//                $aUser['transfer_total'] = Tools::flowToGB($aUser['transfer_total']).'GB';
+//                $aUser['transfer_enable'] = Tools::flowToGB($aUser['transfer_enable']).'GB';
+//                $aUser['last_use_time'] = date('Y-m-d H:i:s', $aUser['last_use_time']);
+//            } else {
+//                $aUser = ["not have id" => $iUserId];
+//            }
+//
+//            $this->sendMessage(json_encode($aUser, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 查找订单
+        // orderFindByUser 11
+        if (strpos($sText, '/orderFindByUser') === 0 || strpos($sText, '\/orderFindByUser') === 0) {
+            
+//            list(, $iUserId) = explode(" ", $sText, 2);
+//            
+//            $aOrder = Order::where("user_id", $iUserId)->get()->toArray();
+//            
+//            if ($aOrder) {
+//                $aOrderNew = [];
+//                foreach ($aOrder as $k => $v) {
+//                    $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
+//                    $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
+//                    $v['product_content'] = json_decode($v['product_content']);
+//                    $aOrderNew[] = $v;
+//                }
+//            } else {
+//                $aOrderNew = ["not have id" => $iUserId];
+//            }
+//            
+//            $this->sendMessage(json_encode($aOrderNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 回复工单
+        // /reply 11 + /s 你好
+        if (strpos($sText, '/reply') === 0) {
+            
+            // 先清除一遍,只进行一个进程
+            $oTgStep->clearByFromId($aData["fromId"]);
+                 
+            $iTicketId = str_replace('/reply', '', $sText);
+            $iTicketId = (int) trim($iTicketId);
+            
+            $oTgStep->add($aData['fromId'], 'reply', 1, ["ticketId" => $iTicketId]);
+            
+            $sMessage = "将回复工单【".$iTicketId."】,请输入回复内容。";
+
+            $this->sendMessage($sMessage);
+            
+            Http::response(200, 'ok');
+            
+        }
+        
+        // 快捷回复工单
+        // /ry 11 你好
+        if (strpos($sText, '/ry') === 0 || strpos($sText, '\/ry') === 0) {
+            
+//            try {
+//                $sText = $this->trimText($sText, '/ry');
+//                
+//                list($iTicketId, $sText) = explode(" ", $sText, 2);
+//                
+//                $oHttp = new Http();
+//                
+//                $oHttp->sMethod = "put";
+//                $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/ticket/".$iTicketId;
+//                $oHttp->bIsJson = true;
+//                $aData['comment'] = $sText;
+//                $aData['admin_name'] = $aUpdate["message"]["from"]["first_name"];
+//                $oHttp->aData = $aData;
+//                
+//                $r = @json_decode($oHttp->send(), true);
+//                
+//                // 不论失败成功都清除 step
+//                $oTgStep->clearByFromId($aUpdate["message"]["from"]["id"]);
+//                
+//                if ($r["ret"] == 1) {
+//                    $sMessage = "成功";
+//                } else {
+//                    $sMessage = "失败";
+//                    Http::response(200, json_encode($aData));
+//                }
+//                
+//                $this->sendMessage($sMessage);
+//                
+//                Http::response(200, 'ok');
+//                
+//            } catch (Exception $e) {
+//                
+//                $sMessage = "发生错误: " . $e->getMessage();
+//                
+//                $this->sendMessage($sMessage);
+//                
+//                Http::response(200, '内部服务器错误');
+//                
+//            }
+            
+        }
+        
+        // 复制节点
+        // /nodeCopy 11
+        if (strpos($sText, '/nodeCopy') === 0 || strpos($sText, '\/nodeCopy') === 0) {
+            
+//            list(, $iNodeId) = explode(" ", $sText, 2);
+//            
+//            $oHttp = new Http();
+//            
+//            $oHttp->sMethod = "post";
+//            $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/node/".$iNodeId."/copy";
+//            $oHttp->bIsJson = true;
+//            $oHttp->aData = $aData;
+//            
+//            $r = @json_decode($oHttp->send(), true);
+//            
+//            if ($r["ret"] == 1) {
+//                $sMessage = "成功";
+//            } else {
+//                $sMessage = "失败";
+//                Http::response(500, json_encode($aData));
+//            }
+//            
+//            $this->sendMessage($sMessage);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 用户报表
+        // /reportUser_day_7 && /reportUser_date_2025-02-02 && /reportUser_date_2025-02-02_2025-03-03
+        if (strpos($sText, '/reportUser') === 0 || strpos($sText, '\/reportUser') === 0) {
+            
+//            @list(, $sOption1, $sOption2, $sOption3) = explode("_", $sText, 4);
+//            
+//            $sMsg = '?';
+//            
+//            if ($sOption1 == 'day') {
+//                
+//                $sMsg = (new ServiceTgReportUser())->ByDay($sOption2);
+//                
+//            }
+//            
+//            if ($sOption1 == 'date') {
+//                $sMsg = (new ServiceTgReportUser())->ByDate($sOption2, $sOption3);
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 优惠卷报表
+        // /reportCoupon#7
+        if (strpos($sText, '/reportCoupon') === 0 || strpos($sText, '\/reportCoupon') === 0) {
+//            try {
+//                @list($sCmd, $iDay) = explode("#", $sText, 2);
+//                
+//                // 确保 $iDay 是一个有效的数字
+//                if (!is_numeric($iDay) || $iDay < 0) {
+//                    $this->sendMessage('无效的天数参数');
+//                    Http::response(200, '内部服务器错误');
+//                }
+//
+//                $sStartTime = strtotime("-$iDay days");
+//
+//                $aOrderList = Order::where('update_time', '>=', $sStartTime)
+//                        ->whereIn('status', ['activated', 'pending_activation']) // 添加状态条件
+//                        ->select('coupon',
+//                                 \App\Services\DB::raw('count(*) as total'),
+//                                 \App\Services\DB::raw('SUM(price) as total_price'))
+//                        ->groupBy('coupon')
+//                        ->get()
+//                        ->toArray();
+//
+//                $sMsg = '从 '.date("Y-m-d H:i:s", $sStartTime);
+//                foreach ($aOrderList as $row) {
+//                    $coupon = str_replace('.', '#', $row['coupon']);
+//                    if (!$coupon) {
+//                        $coupon = '无';
+//                    }
+//                    $sMsg .= "\n\n";
+//                    $sMsg .= $coupon . ' - ' . $row['total_price'] . ' / ' . $row['total'];
+//                }
+//
+//                $this->sendMessage($sMsg);
+//                
+//                Http::response(200, 'ok');
+//            } catch (Exception $e) {
+//                // 处理异常
+//                $errorMsg = '发生错误: ' . $e->getMessage();
+//                $this->sendMessage($errorMsg);
+//                
+//                // 返回错误响应
+//                Http::response(200, '内部服务器错误');
+//            }
+        }
+
+
+        // 节点列表(简洁)
+        // /nodeList
+        if (strpos($sText, '/nodeList') === 0 || strpos($sText, '\/nodeList') === 0) {
+            
+//            $aNodeList = Node::where('type', 1)->orderBy('name', 'asc')->get()->toArray();
+//            
+//            $sMsg = '';
+//            foreach ($aNodeList as $row) {
+//                $sMsg .= "\n\n";
+//                $sMsg .= $row['name'].', id:'.$row['id'].', duck:'.$row['duck_code'].', zf:'.$row['zhuanfa_code'].', sort:'.$row['sort'];
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 添加duck
+        // /duckAdd jp01
+        if (strpos($sText, '/duckAdd') === 0 || strpos($sText, '\/duckAdd') === 0) {
+            
+//            list($sCmd, $sCode) = explode(" ", $sText, 2);
+//            
+//            try {
+//                $oDucks = new Ducks();
+//                $oDucks->code = $sCode;
+//
+//                if ($oDucks->save()) {
+//                    $sMsg = "成功";
+//                } else {
+//                    $sMsg = "失败";
+//                }
+//            } catch (\Exception $e) {
+//                $sMsg = json_encode($e->getMessage());
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 查找duck
+        // /duckFind jp01
+        if (strpos($sText, '/duckFind') === 0 || strpos($sText, '\/duckFind') === 0) {
+            
+//            list($sCmd, $sCode) = explode(" ", $sText, 2);
+//            
+//            $aData = Ducks::where('code', $sCode)->first()->toArray();
+//            
+//            $aData['use_width'] = Tools::flowToGB($aData['use_width']).'GB';
+//            $aData['max_width'] = Tools::flowToGB($aData['max_width']).'GB';
+//            $aData['today_width'] = Tools::flowToGB($aData['today_width']).'GB';
+//            
+//            $this->sendMessage(json_encode($aData, JSON_PRETTY_PRINT));
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 添加zhuanfa
+        // /zhuanfaAdd jp01
+        if (strpos($sText, '/zhuanfaAdd') === 0 || strpos($sText, '\/zhuanfaAdd') === 0) {
+            
+//            list($sCmd, $sCode) = explode(" ", $sText, 2);
+//            
+//            try {
+//                $oZhuanfas = new Zhuanfas();
+//                $oZhuanfas->code = $sCode;
+//
+//                if ($oZhuanfas->save()) {
+//                    $sMsg = "成功";
+//                } else {
+//                    $sMsg = "失败";
+//                }
+//            } catch (\Exception $e) {
+//                $sMsg = json_encode($e->getMessage());
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 删除duck
+        // /duckDel jp01
+        if (strpos($sText, '/duckDel') === 0 || strpos($sText, '\/duckDel') === 0) {
+            
+//            list($sCmd, $sCode) = explode(" ", $sText, 2);
+//            
+//            try {
+//                $oDucks = Ducks::where("code", $sCode)->first();
+//
+//                if ($oDucks) {
+//                    // 尝试删除记录
+//                    $deleted = $oDucks->delete();
+//
+//                    if ($deleted) {
+//                        // 删除成功
+//                        $sMsg = "成功";
+//                    } else {
+//                        // 删除失败
+//                        $sMsg = "失败";
+//                    }
+//                } else {
+//                    // 找不到记录
+//                    $sMsg = "找不到记录";
+//                }
+//            } catch (\Exception $e) {
+//                // 捕获异常并返回错误信息
+//                $sMsg = json_encode($e->getMessage());
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 删除node
+        // /duckDel jp01
+        if (strpos($sText, '/nodeDel') === 0 || strpos($sText, '\/nodeDel') === 0) {
+            
+//            list($sCmd, $iId) = explode(" ", $sText, 2);
+//            
+//            $sMsg = '?';
+//            
+//            try {
+//                $oNode = Node::where("id", $iId)->first();
+//
+//                if ($oNode) {
+//                    // 尝试删除记录
+//                    $deleted = $oNode->delete();
+//
+//                    if ($deleted) {
+//                        // 删除成功
+//                        $sMsg = "成功";
+//                    } else {
+//                        // 删除失败
+//                        $sMsg = "失败";
+//                    }
+//                } else {
+//                    // 找不到记录
+//                    $sMsg = "找不到记录";
+//                }
+//            } catch (\Exception $e) {
+//                // 捕获异常并返回错误信息
+//                $sMsg = json_encode($e->getMessage());
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 删除zhuanfa
+        // /zhuanfaDel jp01
+        if (strpos($sText, '/zhuanfaDel') === 0 || strpos($sText, '\/zhuanfaDel') === 0) {
+            
+//            list($sCmd, $sCode) = explode(" ", $sText, 2);
+//            
+//            try {
+//                $oZhuanfas = Zhuanfas::where("code", $sCode)->first();
+//
+//                if ($oZhuanfas) {
+//                    // 尝试删除记录
+//                    $deleted = $oZhuanfas->delete();
+//
+//                    if ($deleted) {
+//                        // 删除成功
+//                        $sMsg = "成功";
+//                    } else {
+//                        // 删除失败
+//                        $sMsg = "失败";
+//                    }
+//                } else {
+//                    // 找不到记录
+//                    $sMsg = "找不到记录";
+//                }
+//            } catch (\Exception $e) {
+//                // 捕获异常并返回错误信息
+//                $sMsg = json_encode($e->getMessage());
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 修改duck
+        // /duckOption@end_date@jp01 2025_02_02
+        // /duckOption@max_width@jp01 1.66#tb
+        if (strpos($sText, '/duckOption') === 0 || strpos($sText, '\/duckOption') === 0) {
+            
+//            list($sCmd, $sSet) = explode(" ", $sText, 2);
+//            list(, $sField, $sCode) = explode("#", $sCmd, 3);
+//        
+//            if ($sSet) {
+//                @list($iWidth, $sWidthType) = explode("|", $sSet, 2);
+//            } else {
+//                $sMsg = "没有参数";
+//            }
+//            
+//            
+//            if ($sWidthType == 'tb') {
+//                $sSet = Tools::tomTbToB($iWidth);
+//            }
+//            
+//            if ($sWidthType == 'gb') {
+//                $sSet = Tools::tomGbToB($iWidth);
+//            }
+//            
+//            $sMsg = '?';
+//            try {
+//                
+//                $oDuck = Ducks::where('code', $sCode)->first();
+//                
+//                if (!$oDuck) {
+//                    $sMsg = "没有这个code";
+//                } else {
+//                    $oDuck->$sField = $sSet;
+//                    if ($oDuck->save()) {
+//                        $sMsg = "成功"; // 保存成功
+//                    } else {
+//                        $sMsg = "失败"; // 保存失败
+//                    }
+//                }
+//                
+//            } catch (\Illuminate\Database\QueryException $e) {
+//                
+//                $sMsg = json_encode($e->getMessage());
+//                
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 修改zhuanfa
+        // /zhuanfaOption-end_date-jp01 2025_02_02
+        // /zhuanfaOption-max_width-jp01 1.66#tb
+        if (strpos($sText, '/zhuanfaOption') === 0 || strpos($sText, '\/zhuanfaOption') === 0) {
+            
+//            list($sCmd, $sSet) = explode(" ", $sText, 2);
+//            list(, $sField, $sCode) = explode("-", $sCmd, 3);
+//            @list($iWidth, $sWidthType) = explode("#", $sSet, 2);
+//            
+//            if ($sWidthType == 'tb') {
+//                $sSet = Tools::tomTbToB($iWidth);
+//            }
+//            
+//            if ($sWidthType == 'gb') {
+//                $sSet = Tools::tomGbToB($iWidth);
+//            }
+//            
+//            $sMsg = '?';
+//            try {
+//                
+//                $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
+//                
+//                if (!$oZhuanfas) {
+//                    $sMsg = "没有这个code";
+//                } else {
+//                    $oZhuanfas->$sField = $sSet;
+//                    if ($oZhuanfas->save()) {
+//                        $sMsg = "成功"; // 保存成功
+//                    } else {
+//                        $sMsg = "失败"; // 保存失败
+//                    }
+//                }
+//                
+//            } catch (\Illuminate\Database\QueryException $e) {
+//                
+//                $sMsg = json_encode($e->getMessage());
+//                
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 转发重置
+        // /zhuanfaReset-youshi 2025-02-02
+        if (strpos($sText, '/zhuanfaReset') === 0 || strpos($sText, '\/zhuanfaReset') === 0) {
+            
+//            list($sCmd, $sDate) = explode(" ", $sText, 2);
+//            list(, $sCode) = explode("-", $sCmd, 2);
+//            
+//            $sMsg = '?';
+//            try {
+//                
+//                $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
+//                
+//                if (!$oZhuanfas) {
+//                    $sMsg = "没有这个code";
+//                } else {
+//                    $oZhuanfas->use_width = 0;
+//                    $oZhuanfas->end_date = $sDate;
+//                    if ($oZhuanfas->save()) {
+//                        $sMsg = "成功"; // 保存成功
+//                    } else {
+//                        $sMsg = "失败"; // 保存失败
+//                    }
+//                }
+//                
+//            } catch (\Illuminate\Database\QueryException $e) {
+//                
+//                $sMsg = json_encode($e->getMessage());
+//                
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // duck list
+        // /duckList
+        if (strpos($sText, '/duckList') === 0 || strpos($sText, '\/duckList') === 0) {
+            
+//            $aDuckList = Ducks::orderBy('code')->get()->toArray();
+//            
+//            $aMsgData = [];
+//            foreach ($aDuckList as $k => $v) {
+//                $v['use_width'] = Tools::flowToGB($v['use_width']).'g';
+//                $v['max_width'] = Tools::flowToGB($v['max_width']).'g';
+//                $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
+//                $aMsgData[] = $v;
+//            }
+//            
+//            $this->sendMessage(json_encode($aMsgData, JSON_PRETTY_PRINT));
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // zhuanfa list
+        // /zhuanfaList
+        if (strpos($sText, '/zhuanfaList') === 0 || strpos($sText, '\/zhuanfaList') === 0) {
+            
+//            $aZhuanfaList = Zhuanfas::orderBy('code')->get()->toArray();
+//            
+//            $aMsgData = [];
+//            foreach ($aZhuanfaList as $k => $v) {
+//                $v['use_width'] = Tools::flowToTB($v['use_width'])."t";
+//                $v['max_width'] = Tools::flowToTB($v['max_width']).'t';
+//                $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
+//                $aMsgData[] = $v;
+//            }
+//            
+//            $this->sendMessage(json_encode($aMsgData, JSON_PRETTY_PRINT));
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 节点设置变更
+        // /nodeOption@name@1 haha
+        if (strpos($sText, '/nodeOption') === 0 || strpos($sText, '\/nodeOption') === 0) {
+            
+//            list($sCmd, $sSet) = explode(" ", $sText, 2);
+//            
+//            list(, $sField, $iNodeId) = explode("#", $sCmd, 3);
+//            
+//            switch ($sField) {
+//                case "config":
+//                    $sField = "custom_config";
+//                    break;
+//                case "duck":
+//                    $sField = "duck_code";
+//                    break;
+//                case "zhuanfa":
+//                    $sField = "zhuanfa_code";
+//                    break;
+//                default:
+//                    $sField = $sField;
+//                    break;
+//            }
+//            
+//            $sMsg = '?';
+//            try {
+//                
+//                $oNode = Node::find($iNodeId);
+//                
+//                if (!$oNode) {
+//                    $sMsg = "没有这个id";
+//                } else {
+//                    $oNode->$sField = $sSet;
+//                    $oNode->save();
+//                    
+//                    $sMsg = "ok";
+//                }
+//                
+//            } catch (\Illuminate\Database\QueryException $e) {
+//                
+//                $sMsg = "数据库操作失败";
+//                
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+            
+        }
+        
+        // 节点搜索
+        // /nodeLike_duck_type1 jp02
+        if (strpos($sText, '/nodeLike') === 0 || strpos($sText, '\/nodeLike') === 0) {
+                
+//            @list($sCmd, $sLike) = explode(" ", $sText);
+//            
+//            @list(, $sField, $sMod) = explode("#", $sCmd, 3);
+//            
+//            switch ($sField) {
+//                case "port":
+//                    $sField = "custom_config";
+//                    break;
+//                case "config":
+//                    $sField = "custom_config";
+//                    break;
+//                case "duck":
+//                    $sField = "duck_code";
+//                    break;
+//                case "zhuanfa":
+//                    $sField = "zhuanfa_code";
+//                    break;
+//                default:
+//                    $sField = $sField;
+//                    break;
+//            }
+//            
+//            $sMsg = '?';
+//        
+//            try {
+//                
+//                $oNodeList = Node::where($sField, 'like', '%' . $sLike . '%');
+//                
+//                if ($sMod == 'type1') {
+//                    $oNodeList->where('type', 1);
+//                }
+//                
+//                $aNodeList = $oNodeList->orderBy('type', 'desc')->orderBy('name', 'asc')->get()->toArray();
+//                
+//            } catch (\Illuminate\Database\QueryException $e) {
+//                
+//                $sMsg = '字段不存在';
+//                
+//            }
+//            
+//            if (empty($aNodeList)) {
+//                
+//                $sMsg = "没有";
+//                
+//            } else {
+//                
+//                $aNodeListNew = [];
+//                foreach ($aNodeList as $row) {
+//                    
+//                    $row['custom_config'] = json_decode($row['custom_config']);
+//                    $row['dynamic_rate_config'] = json_decode($row['dynamic_rate_config']);
+//                    $row['node_bandwidth_limit'] = Tools::flowToGB($row['node_bandwidth_limit']).'GB';
+//                    $row['node_bandwidth'] = Tools::flowToGB($row['node_bandwidth']).'GB';
+//                    $row['node_heartbeat'] = date('Y-m-d H:i:s', $row['node_heartbeat']);
+//                    unset($row['is_dynamic_rate']);
+//                    unset($row['dynamic_rate_type']);
+//                    unset($row['dynamic_rate_config']);
+//                    unset($row['bandwidthlimit_resetday']);
+//                    unset($row['is_dynamic_rate']);
+//                    unset($row['password']);
+//                    
+////                    $aNodeListNew[] = $row;
+//                    
+//                    $sMsg = json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+//                    
+//                    $this->sendMessage($sMsg);
+//                }
+//                
+////                $sMsg = json_encode($aNodeListNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+//                Http::response(200, 'ok');
+//            }
+            
+            $this->sendMessage($sMsg);
+            
+            Http::response(200, 'ok');
+            
+        }
+       
+        // 工单查找
+        // /ticketFind 11
+//        if (strpos($sText, '/ticketFind') === 0) {
+//            
+//            $iTicketId = $this->trimText($sText, '/ticketFind');
+//            
+//            $aTicket = Ticket::where("id", $iTicketId)->first()->toArray();
+//            
+//            $sMsg = "title:".$aTicket['title']."。\n";
+//            
+//            $aTicketContent = json_decode($aTicket['content'], true);
+//            
+//            if (!is_array($aTicketContent[0])) {
+//                $aTicketContent[] = $aTicketContent;
+//            }
+//            
+//            foreach ($aTicketContent as $row) {
+//                $sMsg .= "\n";
+//                $sMsg .= "name:".$row['commenter_name']."\n";
+//                $sMsg .= "comment:".$row['comment']."\n";
+//            }
+//            
+//            $this->sendMessage($sMsg);
+//            
+//            Http::response(200, 'ok');
+//            
+//        }
+        
+        Http::response(200, '无');
+
+    }
+    
+    private function trimText($sText, $sTrim)
+    {
+        $sText = ltrim($sText, $sTrim);
+        $sText = trim($sText);
+        
+        return $sText;
+    }
+    
+    private function sendMessage($sText = '?') {
+        
+        if ($_ENV['is_loc'] === true) {
+            echo "
";
+            var_dump($sText);
+        } else {
+            $url = "https://api.telegram.org/bot$this->sApiToken/sendMessage?chat_id=$this->sApiChatId&text=" . urlencode($sText);
+            file_get_contents($url);
+        }
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Article_.php b/src/Services/Tg/Hook/Mod/Article_.php
new file mode 100644
index 00000000..c2be152c
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Article_.php
@@ -0,0 +1,142 @@
+get()->toArray();
+        
+        foreach ($aArticleList as &$row) { // 使用引用来修改原数组
+            unset($row['updated_at']); // 移除 updated_at 字段
+            unset($row['created_at']); // 移除 created_at 字段
+            $this->oTGHttp->sendToTG(json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+        }
+        
+        $this->oHttp::response(200, 'ok');
+    }
+    
+    public function Find($aParam)
+    {
+        $iId = $aParam['aArg'][1];
+        
+        $aSingle = ModelArticle::find($iId)->toArray();
+        
+        unset($aSingle['updated_at']);
+        unset($aSingle['created_at']);
+        
+        return json_encode($aSingle, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+    }
+
+    
+    public function Like($aParams)
+    {
+        $aArticleList = ModelArticle::where($this->cmdGood($aParams['aOption'][1]), 'like', '%' . $aParams['aArg'][1] . '%')
+            ->orderBy("user_name")
+            ->get()
+            ->toArray();
+
+        if (empty($aArticleList)) {
+            $this->oTGHttp->sendToTG("没有");
+        } else {
+            foreach ($aArticleList as &$row) { // 使用引用来修改原数组
+                unset($row['updated_at']); // 移除 updated_at 字段
+                unset($row['created_at']); // 移除 created_at 字段
+                $this->oTGHttp->sendToTG(json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+            }
+        }
+
+        $this->oHttp::response(200, 'ok');
+    }
+    
+    public function Clone($aParam)
+    {
+        $iId = $aParam['aArg'][1];
+        
+        // 查找文章
+        $aArticle = ModelArticle::find($iId);
+        
+        if ($aArticle) {
+            // 复制文章
+            $newArticle = $aArticle->replicate();
+            
+            // 如果需要,可以修改新文章的某些字段,例如标题或状态
+//            $newArticle->title = $newArticle->title . ' - Copy'; // 修改标题
+            // $newArticle->status = 'draft'; // 例如,将状态设置为草稿
+            
+            // 保存新文章
+            $newArticle->save();
+            
+            // 发送新文章的 ID 到 Telegram
+            $sMsg = "新文章已创建,ID: " . $newArticle->id;
+            $this->oTGHttp->sendToTG($sMsg);
+            
+            // 返回 HTTP 响应
+            $this->oHttp::response(200, 'ok');
+        } else {
+            throw new \Exception("没有这个id");
+        }
+    }
+    
+    public function Add($aParams)
+    {
+        
+        $newArticle = new ModelArticle();
+        $newArticle->user_name = $aParams['aArg'][1];
+        $r = $newArticle->save();
+        
+        $this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+        
+        $this->oHttp::response(200, 'ok');
+        
+    }
+    
+    public function Del($aParams)
+    {
+        
+        $article = ModelArticle::find($aParams['aArg'][1]);
+
+        if ($article) {
+            $r = $article->delete();
+        } else {
+            $r = false;
+        }
+        
+        $this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+        
+        $this->oHttp::response(200, 'ok');
+        
+    }
+    
+    // /ArticleSet__id__user_name xxx
+    public function Set($aParams)
+    {
+        $sField = $this->cmdGood($aParams['aOption'][2]);
+
+        $article = ModelArticle::find($aParams['aOption'][1]);
+        
+        $sSet = $aParams['aArg'][1];
+
+        if ($article) {
+            $article->$sField = $sSet;
+
+            $r = $article->save();
+        } else {
+            // 处理未找到的情况
+            throw new \Exception("Article not found");
+        }
+
+        $this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
+        
+        $this->oHttp::response(200, 'ok');
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Base.php b/src/Services/Tg/Hook/Mod/Base.php
new file mode 100644
index 00000000..81c0eda0
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Base.php
@@ -0,0 +1,43 @@
+oHttp = new Http();
+        $this->oTGHttp = new TGHttp();
+    }
+    
+//    protected function cmdGood($sCmd) {
+//        
+//        $sCmdNew = "";
+//        switch ($sCmd) {
+//            case "user":
+//                $sCmdNew = "user_name";
+//                break;
+//            case "project":
+//                $sCmdNew = "project_name";
+//                break;
+//            case "code":
+//                $sCmdNew = "sale_code";
+//                break;
+//            case "condition":
+//                $sCmdNew = "cron_condition";
+//                break;
+//            default:
+//                $sCmdNew = $sCmd;
+//                break;
+//        }
+//        
+//        return $sCmdNew;
+//        
+//    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Cmd.php b/src/Services/Tg/Hook/Mod/Cmd.php
new file mode 100644
index 00000000..042e3115
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Cmd.php
@@ -0,0 +1,47 @@
+ 'tk#find 11',
+            '工单回复'  => 'tk#ry__11 你好',
+            '节点like'  => 'node#like__id 1',
+            '节点set'  => 'node#set__12__name 日本01',
+            '节点del'  => 'node#del 25',
+            '节点list'  => 'node#list',
+            '节点clone'  => 'node#clone 24',
+            '转发list'  => 'zf#list',
+            '转发set'  => 'zf#set__youshi__use_width 3#tb',
+            '转发del'  => 'zf#del hk02',
+            '转发add'  => 'zf#add hk02',
+            '转发重置'  => 'zf#reset__youshi 2028-01-01',
+            '机器del'  => 'duck#del hk02',
+            '机器list'  => 'duck#list',
+            '机器find'  => 'duck#find hk01',
+            '机器add'  => 'duck#add hk01',
+            '用户注册'
+            '用户报表day'  => 'user#report__day__3',
+            '用户报表date'  => 'user#report__date__2025-01-01',
+            '用户报表date到date'  => 'user#report__date__2025-01-01__2026-01-01',
+            '用户查找'  => 'user#find 1',
+            '订单从优惠码分组(默认0=24h)'  => 'order#groupBySaleCode 3',
+            '访客统计day'
+            '访客统计date'
+            '访客统计date到date'
+        ];
+        
+        return json_encode($aCmdList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Duck.php b/src/Services/Tg/Hook/Mod/Duck.php
new file mode 100644
index 00000000..461b2641
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Duck.php
@@ -0,0 +1,144 @@
+get()->toArray();
+        
+        $aMsgData = [];
+        foreach ($aDuckList as $k => $v) {
+            $v['use_width'] = Tools::flowToGB($v['use_width']).'g';
+            $v['max_width'] = Tools::flowToGB($v['max_width']).'g';
+            $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
+            $aMsgData[] = $v;
+        }
+        
+        $sMsg = json_encode($aMsgData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+        return $sMsg;
+        
+    }
+    
+    public function Add($aParam)
+    {
+        
+//        list($sCmd, $sCode) = explode(" ", $sText, 2);
+        
+        $sCode = $aParam['aArg'][1];
+        
+        $oDucks = new ModelDuck();
+        $oDucks->code = $sCode;
+
+        if ($oDucks->save()) {
+            $sMsg = "成功";
+        } else {
+            $sMsg = "失败";
+        }
+    
+        return $sMsg;
+        
+    }
+    
+    public function Find($aParam)
+    {
+        
+//        list($sCmd, $sCode) = explode(" ", $sText, 2);
+        
+        $sCode = $aParam['aArg'][1];
+        
+        $aData = ModelDuck::where('code', $sCode)->first()->toArray();
+        
+        $aData['use_width'] = Tools::flowToGB($aData['use_width']).'GB';
+        $aData['max_width'] = Tools::flowToGB($aData['max_width']).'GB';
+        $aData['today_width'] = Tools::flowToGB($aData['today_width']).'GB';
+        
+        $sMsg = json_encode($aData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+        return $sMsg;
+        
+    }
+    
+    public function Del($aParam)
+    {
+        
+//        list($sCmd, $sCode) = explode(" ", $sText, 2);
+        
+        $sCode = $aParam['aArg'][1];
+        
+        $oDucks = ModelDuck::where("code", $sCode)->first();
+
+        if ($oDucks) {
+            // 尝试删除记录
+            $deleted = $oDucks->delete();
+
+            if ($deleted) {
+                // 删除成功
+                $sMsg = "成功";
+            } else {
+                // 删除失败
+                $sMsg = "失败";
+            }
+        } else {
+            // 找不到记录
+            $sMsg = "找不到记录";
+        }
+        
+        return $sMsg;
+        
+    }
+    
+    public function Set($aParam)
+    {
+        
+//        list($sCmd, $sSet) = explode(" ", $sText, 2);
+//        list(, $sField, $sCode) = explode("#", $sCmd, 3);
+        
+        $sSet = $aParam['aArg'][1];
+        $sCode = $aParam['aOption'][1];
+        $sField = $aParam['aOption'][2];
+    
+        if ($sSet) {
+            @list($iWidth, $sWidthType) = explode("#", $sSet, 2);
+        } else {
+            $sMsg = "没有参数";
+        }
+        
+        
+        if ($sWidthType == 'tb') {
+            $sSet = Tools::tomTbToB($iWidth);
+        }
+        
+        if ($sWidthType == 'gb') {
+            $sSet = Tools::tomGbToB($iWidth);
+        }
+        
+        $sMsg = '?';
+        
+        $oDuck = ModelDuck::where('code', $sCode)->first();
+        
+        if (!$oDuck) {
+            $sMsg = "没有这个code";
+        } else {
+            $oDuck->$sField = $sSet;
+            if ($oDuck->save()) {
+                $sMsg = "成功"; // 保存成功
+            } else {
+                $sMsg = "失败"; // 保存失败
+            }
+        }
+        
+        return $sMsg;
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Node.php b/src/Services/Tg/Hook/Mod/Node.php
new file mode 100644
index 00000000..f7c9e1e0
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Node.php
@@ -0,0 +1,202 @@
+sMethod = "post";
+        $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/node/".$iNodeId."/copy";
+        $oHttp->bIsJson = true;
+        $oHttp->aData = [
+            'chatId'    => $aParam['aOther']['chatId'],
+            'fromId'    => $aParam['aOther']['fromId']
+        ];
+        
+        $r = @json_decode($oHttp->send(), true);
+        
+        if ($r["ret"] == 1) {
+            $sMessage = "成功";
+        } else {
+            $sMessage = "失败";
+        }
+        
+        return $sMessage;
+        
+    }
+    
+    public function List()
+    {
+        
+        $aNodeList = ModelNode::where('type', 1)->orderBy('name', 'asc')->get()->toArray();
+        
+        $sMsg = '';
+        foreach ($aNodeList as $row) {
+            $sMsg .= "\n\n";
+            $sMsg .= $row['name'].', id:'.$row['id'].', duck:'.$row['duck_code'].', zf:'.$row['zhuanfa_code'].', sort:'.$row['sort'];
+        }
+        
+        return $sMsg;
+        
+    }
+    
+    public function Like($aParam)
+    {
+        
+//        @list($sCmd, $sLike) = explode(" ", $sText);
+//        
+//        @list(, $sField, $sMod) = explode("#", $sCmd, 3);
+        
+        $sLike = $aParam['aArg'][1];
+        $sField = $aParam['aOption'][1];
+        @$sMod = $aParam['aOption'][2];
+        
+        switch ($sField) {
+            case "port":
+                $sField = "custom_config";
+                break;
+            case "config":
+                $sField = "custom_config";
+                break;
+            case "duck":
+                $sField = "duck_code";
+                break;
+            case "zhuanfa":
+                $sField = "zhuanfa_code";
+                break;
+            default:
+                $sField = $sField;
+                break;
+        }
+        
+        $sMsg = '?';
+    
+        $oNodeList = ModelNode::where($sField, 'like', '%' . $sLike . '%');
+        
+        if ($sMod == 'type1') {
+            $oNodeList->where('type', 1);
+        }
+        
+        $aNodeList = $oNodeList->orderBy('type', 'desc')->orderBy('name', 'asc')->get()->toArray();
+            
+        if (empty($aNodeList)) {
+            
+            $sMsg = "没有";
+            
+        } else {
+            
+            $aNodeListNew = [];
+            foreach ($aNodeList as $row) {
+                
+                $row['custom_config'] = json_decode($row['custom_config']);
+                $row['dynamic_rate_config'] = json_decode($row['dynamic_rate_config']);
+                $row['node_bandwidth_limit'] = Tools::flowToGB($row['node_bandwidth_limit']).'GB';
+                $row['node_bandwidth'] = Tools::flowToGB($row['node_bandwidth']).'GB';
+                $row['node_heartbeat'] = date('Y-m-d H:i:s', $row['node_heartbeat']);
+                unset($row['is_dynamic_rate']);
+                unset($row['dynamic_rate_type']);
+                unset($row['dynamic_rate_config']);
+                unset($row['bandwidthlimit_resetday']);
+                unset($row['is_dynamic_rate']);
+                unset($row['password']);
+                
+                $sMsg = json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                
+                $this->oTGHttp->sendToTG($sMsg);
+                
+            }
+            
+        }
+        $this->oHttp::response(200, 'ok');
+    }
+    
+    public function Set($aParam)
+    {
+        
+//        list($sCmd, $sSet) = explode(" ", $sText, 2);
+//        
+//        list(, $sField, $iNodeId) = explode("#", $sCmd, 3);
+        
+        $sSet = $aParam['aArg'][1];
+        $iNodeId = $aParam['aOption'][1];
+        $sField = $aParam['aOption'][2];
+        
+        switch ($sField) {
+            case "config":
+                $sField = "custom_config";
+                break;
+            case "duck":
+                $sField = "duck_code";
+                break;
+            case "zhuanfa":
+                $sField = "zhuanfa_code";
+                break;
+            default:
+                $sField = $sField;
+                break;
+        }
+        
+        $sMsg = '?';
+        
+        $oNode = ModelNode::find($iNodeId);
+        
+        if (!$oNode) {
+            $sMsg = "没有这个id";
+        } else {
+            $oNode->$sField = $sSet;
+            $oNode->save();
+            
+            $sMsg = "ok";
+        }
+            
+        return $sMsg;
+        
+    }
+    
+    public function Del($aParam)
+    {
+        
+//        list($sCmd, $iId) = explode(" ", $sText, 2);
+        $iId = $aParam['aArg'][1];
+        
+        $sMsg = '?';
+        
+        $oNode = ModelNode::where("id", $iId)->first();
+
+        if ($oNode) {
+            // 尝试删除记录
+            $deleted = $oNode->delete();
+
+            if ($deleted) {
+                // 删除成功
+                $sMsg = "成功";
+            } else {
+                // 删除失败
+                $sMsg = "失败";
+            }
+        } else {
+            // 找不到记录
+            $sMsg = "找不到记录";
+        }
+        
+        return $sMsg;
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Order.php b/src/Services/Tg/Hook/Mod/Order.php
new file mode 100644
index 00000000..ace69a02
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Order.php
@@ -0,0 +1,79 @@
+get()->toArray();
+        
+        if ($aOrder) {
+            $aOrderNew = [];
+            foreach ($aOrder as $k => $v) {
+                $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
+                $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
+                $v['product_content'] = json_decode($v['product_content']);
+                $aOrderNew[] = $v;
+            }
+        } else {
+            $aOrderNew = ["not have id" => $iUserId];
+        }
+        
+        $sMsg = json_encode($aOrderNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+        return $sMsg;
+        
+    }
+    
+    public function GroupBySaleCode($aParam)
+    {
+        
+//        @list($sCmd, $iDay) = explode("#", $sText, 2);
+        
+        if (!isset($aParam['aArg'][1])) {
+            $iDay = 1;
+        } else {
+            $iDay = $aParam['aArg'][1];
+        }
+        
+        // 确保 $iDay 是一个有效的数字
+        if (!is_numeric($iDay) || $iDay < 0) {
+            throw new \Exception("无效的天数参数");
+        }
+
+        $sStartTime = strtotime("-$iDay days");
+
+        $aOrderList = ModelOrder::where('update_time', '>=', $sStartTime)
+                ->whereIn('status', ['activated', 'pending_activation']) // 添加状态条件
+                ->select('coupon',
+                         \App\Services\DB::raw('count(*) as total'),
+                         \App\Services\DB::raw('SUM(price) as total_price'))
+                ->groupBy('coupon')
+                ->get()
+                ->toArray();
+
+        $sMsg = '从 '.date("Y-m-d H:i:s", $sStartTime);
+        foreach ($aOrderList as $row) {
+            $coupon = str_replace('.', '#', $row['coupon']);
+            if (!$coupon) {
+                $coupon = '无';
+            }
+            $sMsg .= "\n\n";
+            $sMsg .= $coupon . ' - ' . $row['total_price'] . ' / ' . $row['total'];
+        }
+
+        return $sMsg;
+    
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/SaleCode.php b/src/Services/Tg/Hook/Mod/SaleCode.php
new file mode 100644
index 00000000..203219e1
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/SaleCode.php
@@ -0,0 +1,51 @@
+sendMessage('无效的天数参数');
+            Http::response(200, '内部服务器错误');
+        }
+
+        $sStartTime = strtotime("-$iDay days");
+
+        $aOrderList = Order::where('update_time', '>=', $sStartTime)
+                ->whereIn('status', ['activated', 'pending_activation']) // 添加状态条件
+                ->select('coupon',
+                         \App\Services\DB::raw('count(*) as total'),
+                         \App\Services\DB::raw('SUM(price) as total_price'))
+                ->groupBy('coupon')
+                ->get()
+                ->toArray();
+
+        $sMsg = '从 '.date("Y-m-d H:i:s", $sStartTime);
+        foreach ($aOrderList as $row) {
+            $coupon = str_replace('.', '#', $row['coupon']);
+            if (!$coupon) {
+                $coupon = '无';
+            }
+            $sMsg .= "\n\n";
+            $sMsg .= $coupon . ' - ' . $row['total_price'] . ' / ' . $row['total'];
+        }
+
+        $this->sendMessage($sMsg);
+        
+        Http::response(200, 'ok');
+    
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Test.php b/src/Services/Tg/Hook/Mod/Test.php
new file mode 100644
index 00000000..8e6cb8ed
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Test.php
@@ -0,0 +1,21 @@
+first()->toArray();
+        
+        $sMsg = "title:".$aTicket['title']."。\n";
+        
+        $aTicketContent = json_decode($aTicket['content'], true);
+        
+        if (!is_array($aTicketContent[0])) {
+            $aTicketContent[] = $aTicketContent;
+        }
+        
+        foreach ($aTicketContent as $row) {
+            $sMsg .= "\n";
+            $sMsg .= "name:".$row['commenter_name']."\n";
+            $sMsg .= "comment:".$row['comment']."\n";
+        }
+        
+        return $sMsg;
+        
+    }
+    
+//    public function Find($aParam)
+//    {
+//        
+////        list(, $iUserId) = explode(" ", $sText, 2);
+//        
+//        $iUserId = $aParam['aArg'][1];
+//        
+//        $aOrder = Order::where("user_id", $iUserId)->get()->toArray();
+//        
+//        if ($aOrder) {
+//            $aOrderNew = [];
+//            foreach ($aOrder as $k => $v) {
+//                $v['create_time'] = date("Y-m-d H:i:m", $v['create_time']);
+//                $v['update_time'] = date("Y-m-d H:i:m", $v['update_time']);
+//                $v['product_content'] = json_decode($v['product_content']);
+//                $aOrderNew[] = $v;
+//            }
+//        } else {
+//            $aOrderNew = ["not have id" => $iUserId];
+//        }
+//        
+//        $sMsg = json_encode($aOrderNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+//        
+//        return $sMsg;
+//        
+//    }
+    
+    public function Ry($aParam)
+    {
+        
+//        list($iTicketId, $sText) = explode(" ", $sText, 2);
+        
+        $iTicketId = $aParam['aOption'][1];
+        $sText = $aParam['aArg'][1];
+        $aUpdate = $aParam['aUpdate'];
+        
+        $oHttp = new Http();
+        
+        $oHttp->sMethod = "put";
+        $oHttp->sToUrl = $_ENV['baseUrl']."/api/tg/ticket/".$iTicketId;
+        $oHttp->bIsJson = true;
+        $aData['chatId'] = $aParam['aOther']['chatId'];
+        $aData['fromId'] = $aParam['aOther']['fromId'];
+        $aData['comment'] = $sText;
+        $aData['admin_name'] = $aUpdate["message"]["from"]["first_name"];
+        $oHttp->aData = $aData;
+        
+        $r = @json_decode($oHttp->send(), true);
+        
+        // 不论失败成功都清除 step
+//        $oTgStep->clearByFromId($aUpdate["message"]["from"]["id"]);
+        
+        if ($r["ret"] == 1) {
+            $sMessage = "成功";
+        } else {
+            $sMessage = "失败";
+        }
+        
+        return $sMessage;
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/User.php b/src/Services/Tg/Hook/Mod/User.php
new file mode 100644
index 00000000..deaa0b28
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/User.php
@@ -0,0 +1,75 @@
+toArray();
+            unset($aUser['pass']);
+            unset($aUser['passwd']);
+            unset($aUser['uuid']);
+            unset($aUser['method']);
+            unset($aUser['is_admin']);
+            unset($aUser['theme']);
+            unset($aUser['ga_token']);
+            unset($aUser['ga_enable']);
+            unset($aUser['api_token']);
+            unset($aUser['is_dark_mode']);
+            unset($aUser['locale']);
+            
+            $aUser['transfer_today'] = Tools::flowToGB($aUser['transfer_today']).'GB';
+            $aUser['transfer_total'] = Tools::flowToGB($aUser['transfer_total']).'GB';
+            $aUser['transfer_enable'] = Tools::flowToGB($aUser['transfer_enable']).'GB';
+            $aUser['last_use_time'] = date('Y-m-d H:i:s', $aUser['last_use_time']);
+        } else {
+            $aUser = ["not have id" => $iUserId];
+        }
+
+        $sMsg = json_encode($aUser, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+        return $sMsg;
+        
+    }
+    
+    public function Report($aParam)
+    {
+        
+//        @list(, $sOption1, $sOption2, $sOption3) = explode("_", $sText, 4);
+        
+        @$sOption1 = $aParam['aOption'][1];
+        @$sOption2 = $aParam['aOption'][2];
+        @$sOption3 = $aParam['aOption'][3];
+        @$sOption4 = $aParam['aOption'][4];
+        
+        $sMsg = '?';
+        
+        if ($sOption1 == 'day') {
+            $sMsg = (new ServiceTgReportUser())->ByDay($sOption2);
+        }
+        
+        if ($sOption1 == 'date') {
+            $sMsg = (new ServiceTgReportUser())->ByDate($sOption2, $sOption3);
+        }
+        
+        return $sMsg;
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Hook/Mod/Zf.php b/src/Services/Tg/Hook/Mod/Zf.php
new file mode 100644
index 00000000..340dd40b
--- /dev/null
+++ b/src/Services/Tg/Hook/Mod/Zf.php
@@ -0,0 +1,150 @@
+get()->toArray();
+        
+        $aMsgData = [];
+        foreach ($aZhuanfaList as $k => $v) {
+            $v['use_width'] = Tools::flowToTB($v['use_width'])."t";
+            $v['max_width'] = Tools::flowToTB($v['max_width']).'t';
+            $v['today_width'] = Tools::flowToGB($v['today_width']).'g';
+            $aMsgData[] = $v;
+        }
+        
+        $sMsg = json_encode($aMsgData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+        
+        return $sMsg;
+        
+    }
+    
+    public function Reset($aParam)
+    {
+        
+//        list($sCmd, $sDate) = explode(" ", $sText, 2);
+//        list(, $sCode) = explode("-", $sCmd, 2);
+        
+        $sDate = $aParam['aArg'][1];
+        $sCode = $aParam['aOption'][1];
+        
+        $sMsg = '?';
+        
+        $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
+        
+        if (!$oZhuanfas) {
+            $sMsg = "没有这个code";
+        } else {
+            $oZhuanfas->use_width = 0;
+            $oZhuanfas->end_date = $sDate;
+            if ($oZhuanfas->save()) {
+                $sMsg = "成功"; // 保存成功
+            } else {
+                $sMsg = "失败"; // 保存失败
+            }
+        }
+        
+        return $sMsg;
+        
+    }
+    
+    public function Set($aParam)
+    {
+        
+//        list($sCmd, $sSet) = explode(" ", $sText, 2);
+//        list(, $sField, $sCode) = explode("-", $sCmd, 3);
+//        @list($iWidth, $sWidthType) = explode("#", $sSet, 2);
+        
+        $sSet = $aParam['aArg'][1];
+        $sCode = $aParam['aOption'][1];
+        $sField = $aParam['aOption'][2];
+        
+        @list($iWidth, $sWidthType) = explode("#", $sSet, 2);
+        
+        if ($sWidthType == 'tb') {
+            $sSet = Tools::tomTbToB($iWidth);
+        }
+        
+        if ($sWidthType == 'gb') {
+            $sSet = Tools::tomGbToB($iWidth);
+        }
+        
+        $sMsg = '?';
+        
+        $oZhuanfas = Zhuanfas::where('code', $sCode)->first();
+        
+        if (!$oZhuanfas) {
+            $sMsg = "没有这个code";
+        } else {
+            $oZhuanfas->$sField = $sSet;
+            if ($oZhuanfas->save()) {
+                $sMsg = "成功"; // 保存成功
+            } else {
+                $sMsg = "失败"; // 保存失败
+            }
+        }
+        
+        return $sMsg;
+        
+    }
+    
+    public function Add($aParam)
+    {
+        
+//        list($sCmd, $sCode) = explode(" ", $sText, 2);
+        
+        $sCode = $aParam['aArg'][1];
+        
+        $oZhuanfas = new Zhuanfas();
+        $oZhuanfas->code = $sCode;
+
+        if ($oZhuanfas->save()) {
+            $sMsg = "成功";
+        } else {
+            $sMsg = "失败";
+        }
+    
+        return $sMsg;
+        
+    }
+    
+    public function Del($aParam)
+    {
+        
+//        list($sCmd, $sCode) = explode(" ", $sText, 2);
+        
+        $sCode = $aParam['aArg'][1];
+        
+        $oZhuanfas = Zhuanfas::where("code", $sCode)->first();
+
+        if ($oZhuanfas) {
+            // 尝试删除记录
+            $deleted = $oZhuanfas->delete();
+
+            if ($deleted) {
+                // 删除成功
+                $sMsg = "成功";
+            } else {
+                // 删除失败
+                $sMsg = "失败";
+            }
+        } else {
+            // 找不到记录
+            $sMsg = "找不到记录";
+        }
+        
+        return $sMsg;
+        
+    }
+    
+}
diff --git a/src/Services/Tg/Http.php b/src/Services/Tg/Http.php
new file mode 100644
index 00000000..a9051615
--- /dev/null
+++ b/src/Services/Tg/Http.php
@@ -0,0 +1,30 @@
+sApiToken = Config::obtain('telegram_token');
+        $this->sApiChatId = Config::obtain('telegram_chatid');
+    }
+    
+    public function sendToTG($sMsg)
+    {
+        
+        if ($_ENV['is_loc'] === true) {
+            echo "
";
+            echo($sMsg);
+        } else {
+            $url = "https://api.telegram.org/bot$this->sApiToken/sendMessage?chat_id=$this->sApiChatId&text=" . urlencode($sMsg);
+            file_get_contents($url);
+        }
+        
+    }
+    
+}
diff --git a/src/Services/TomTool/Http.php b/src/Services/TomTool/Http.php
index 298da54d..794e0f36 100755
--- a/src/Services/TomTool/Http.php
+++ b/src/Services/TomTool/Http.php
@@ -6,9 +6,9 @@ namespace App\Services\TomTool;
 
 class Http
 {
-    public $sMethod;
+    public $sMethod = 'get';
     public $aData = [];
-    public $sToUrl;
+    public $sToUrl; // 必须
     public $bIsJson = false; // 默认值为 false
 
     public function send(): string
@@ -48,10 +48,15 @@ class Http
                 }
                 break;
 
-            default:
+            case 'get':
                 // 默认使用 GET 请求
                 curl_setopt($ch, CURLOPT_HTTPGET, true); // 设置为 GET 请求
                 curl_setopt($ch, CURLOPT_URL, $this->sToUrl . '?' . http_build_query($this->aData)); // 设置请求 URL
+                if ($this->bIsJson) {
+                    curl_setopt($ch, CURLOPT_HTTPHEADER, [
+                        'Accept: application/json' // 设置接受的内容类型为 JSON
+                    ]);
+                }
                 break;
         }