Ken 1 天之前
父節點
當前提交
a74b95ba41

+ 1 - 4
app/Http/Controllers/admin/Bet.php

@@ -41,10 +41,7 @@ class Bet extends Controller
     // 模拟下注
     public function fake()
     {
-        $num = rand(1,3);
-        for($i = 0;$i< $num;$i++){
-            BetService::fakeBet();
-        }
+        BetService::randomVirtualBetting(3);
         return $this->success();
     }
 

+ 99 - 32
app/Http/Controllers/admin/Config.php

@@ -2,10 +2,11 @@
 
 namespace App\Http\Controllers\admin;
 
+use Illuminate\Http\JsonResponse;
 use App\Constants\HttpStatus;
-use App\Constants\Util;
 use App\Http\Controllers\Controller;
 use App\Models\Config as ConfigModel;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Validation\ValidationException;
 use Exception;
@@ -13,11 +14,63 @@ use Telegram\Bot\Api;
 use Telegram\Bot\Exceptions\TelegramSDKException;
 use Telegram\Bot\FileUpload\InputFile;
 use App\Services\ConfigService;
-use Google\Service\ServiceManagement\ConfigSource;
 
 class Config extends Controller
 {
 
+    /**
+     * @api {post} /admin/config/pc28Switch 游戏切换(0:pc28 1:急速28)
+     * @apiGroup 配置
+     * @apiUse result
+     * @apiUse header
+     * @apiVersion 1.0.0
+     *
+     * @apiParam {int=0,1} val  (0:pc28 1:极速28)
+     */
+    public function pc28Switch()
+    {
+        try {
+            $params = request()->validate([
+                'val' => ['required', 'integer', 'min:0', 'in:0,1']
+            ]);
+            Cache::put('pc28_switch', $params['val']);
+        } catch (ValidationException $e) {
+            return $this->error(HttpStatus::VALIDATION_FAILED, $e->validator->errors()->first());
+        } catch (Exception $e) {
+            return $this->error(intval($e->getCode()));
+        }
+        return $this->success();
+    }
+
+    /**
+     * @api {get} /admin/config/pcConfig 极速PC28相关配置
+     * @apiGroup 配置
+     * @apiUse result
+     * @apiUse header
+     * @apiVersion 1.0.0
+     *
+     * @apiParam {int} [page=1]
+     * @apiParam {int} [limit=15]
+     */
+    public function pcConfig(): JsonResponse
+    {
+        try {
+            $search['group_id'] = 4;
+            $result = ConfigService::paginate($search);
+            foreach ($result['data'] as $item) {
+                if ($item['field'] == 'pc28_switch') {
+                    $item['val'] = Cache::get('pc28_switch', $item['val']);
+                }
+            }
+        } catch (ValidationException $e) {
+            return $this->error(HttpStatus::VALIDATION_FAILED, $e->validator->errors()->first());
+        } catch
+        (Exception $e) {
+            return $this->error(intval($e->getCode()));
+        }
+        return $this->success($result);
+    }
+
     /**
      *  分页数据
      *
@@ -44,7 +97,8 @@ class Config extends Controller
      *  修改|新增
      *
      */
-    public function store()
+    public
+    function store()
     {
         try {
             $id = request()->post('id', '');
@@ -60,6 +114,17 @@ class Config extends Controller
                     'val' => 'required|string',
                     'remark' => 'required|nullable|string',
                 ];
+                $field = request()->input("field", 'aaa');
+                switch ($field) {
+                    case 'group_language':
+                        $validator['val'] = ['required', 'string', 'in:zh,vi,en'];
+                        break;
+                    case 'pc28_switch':
+                        $validator['val'] = ['required', 'integer', 'in:0,1'];
+                        break;
+                }
+
+
             }
 
 
@@ -83,7 +148,8 @@ class Config extends Controller
     /**
      *  删除
      */
-    public function destroy()
+    public
+    function destroy()
     {
 
         $id = request()->post('id');
@@ -190,7 +256,8 @@ class Config extends Controller
      * @apiUse header
      * @apiVersion 1.0.0
      */
-    public function getAll()
+    public
+    function getAll()
     {
         $list = ConfigModel::where('id', '>', 0)->get();
         $arr = [];
@@ -357,33 +424,33 @@ class Config extends Controller
         return $this->success();
     }
 
-    // public function sendChannelVideo()
-    // {
-    //     $chatId = request()->input('chatId');
-    //     $video = request()->input('video');
-    //     // $config = ConfigModel::where('field', 'channel_message')
-    //     //             ->first()->val;
-    //     // $config = json_decode($config, true);
-    //     $telegram = new Api(config('services.telegram.token'));
-    //     // 发送图片消息
-    //     $response = $telegram->sendVideo([
-    //         'chat_id' => "@{$chatId}",
-    //         'caption' => '这是一个视频消息',
-    //         'video' => InputFile::create($video),
-    //         'protect_content' => false,
-    //     ]);
-
-    //     // 获取消息ID
-    //     $messageId = $response->get('message_id');
-    //     // 获取消息ID
-    //     $messageId = $response->get('message_id');
-    //     // 置顶消息
-    //     $telegram->pinChatMessage([
-    //         'chat_id' => "@{$chatId}",
-    //         'message_id' => $messageId
-    //     ]);
-    //     return $this->success($messageId);
-    // }
+// public function sendChannelVideo()
+// {
+//     $chatId = request()->input('chatId');
+//     $video = request()->input('video');
+//     // $config = ConfigModel::where('field', 'channel_message')
+//     //             ->first()->val;
+//     // $config = json_decode($config, true);
+//     $telegram = new Api(config('services.telegram.token'));
+//     // 发送图片消息
+//     $response = $telegram->sendVideo([
+//         'chat_id' => "@{$chatId}",
+//         'caption' => '这是一个视频消息',
+//         'video' => InputFile::create($video),
+//         'protect_content' => false,
+//     ]);
+
+//     // 获取消息ID
+//     $messageId = $response->get('message_id');
+//     // 获取消息ID
+//     $messageId = $response->get('message_id');
+//     // 置顶消息
+//     $telegram->pinChatMessage([
+//         'chat_id' => "@{$chatId}",
+//         'message_id' => $messageId
+//     ]);
+//     return $this->success($messageId);
+// }
 
 
     /**

+ 3 - 3
app/Http/Controllers/admin/User.php

@@ -53,13 +53,13 @@ class User extends Controller
     public function index(): JsonResponse
     {
         try {
-            request()->validate([
-                'game_id' => ['nullable', 'string', 'min:1'],
+            $search = request()->validate([
+                'page' => ['nullable', 'integer', 'min:1'],
+                'limit' => ['nullable', 'integer', 'min:1'],
                 'member_id' => ['nullable', 'string', 'min:1'],
                 'first_name' => ['nullable', 'string', 'min:1'],
                 'username' => ['nullable', 'string', 'min:1'],
             ]);
-            $search = request()->all();
             $result = UserService::paginate($search);
         } catch (ValidationException $e) {
             return $this->error(HttpStatus::CUSTOM_ERROR, $e->validator->errors()->first());

+ 1 - 0
app/Http/Controllers/api/Home.php

@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
 use App\Models\Message;
 use App\Models\PcIssue;
 use App\Services\BaseService;
+use App\Services\IssueService;
 use App\Services\PcIssueService;
 use Carbon\Carbon;
 use Illuminate\Support\Facades\DB;

+ 12 - 5
app/Jobs/FiveSecondTaskJob.php

@@ -2,6 +2,7 @@
 
 namespace App\Jobs;
 
+use App\Services\BetService;
 use App\Services\PcIssueService;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldBeUnique;
@@ -46,14 +47,20 @@ class FiveSecondTaskJob implements ShouldQueue
     {
         try {
             Log::error('🚀 开始执行15秒任务: ' . now());
+            //自定义开奖
             PcIssueService::index();
-            IssueService::syncCountdownIssue(); // 提前20秒提醒
 
-            IssueService::syncCloseIssue(); // 同步停止
-            // Log::error('✅ 获取到最新期号: ' . ($latestIssue ?? '无'));
+            // 提前20秒提醒
+            IssueService::syncCountdownIssue();
 
-            // 你的业务逻辑
-            IssueService::getLatestIssue(); // 获取最新的期号
+            // 同步停止
+            IssueService::syncCloseIssue();
+
+            // 获取最新的期号
+            IssueService::getLatestIssue();
+
+            //随机虚拟投注//随机最大人数:3人
+//            BetService::randomVirtualBetting(3);
 
             // 重要:使用类名而不是 self(),避免递归
             FiveSecondTaskJob::dispatch()->delay(now()->addSeconds(15));

+ 24 - 1
app/Models/Config.php

@@ -2,16 +2,39 @@
 
 namespace App\Models;
 
+use App\Services\ConfigService;
+use Illuminate\Support\Facades\App;
+use Illuminate\Support\Facades\Cache;
+
 class Config extends BaseModel
 {
     protected $table = 'config';
-    protected $fillable = ['field', 'val', 'remark','group_id'];
+    protected $fillable = ['field', 'val', 'remark', 'group_id'];
+
     /*
      * group_id
      * 1 系统基础配置
      * 2 频道消息配置
      * 3 用户自定义配置
+     * 4 极速PC28相关配置
      *
      *
      */
+
+    public static function setPc28Switch()
+    {
+        $pc28_switch = Cache::get('pc28_switch');
+        $val = static::where('field', 'pc28_switch')->first()->val;
+        if ($pc28_switch == null) $pc28_switch = $val;
+        if ($pc28_switch != $val) {
+            static::where('field', 'pc28_switch')->update(['val' => $pc28_switch]);
+            $lang = App::getLocale();
+            $group_language = static::where('field', 'group_language')->first()->val;
+            App::setLocale($group_language);
+            $groupText = "------" . lang("已切换为极速PC28") . "------";
+            if ($pc28_switch == 0) $groupText = "-----" . lang("已切换为加拿大PC28") . "------";
+            App::setLocale($lang);
+            ConfigService::asyncBettingGroupNotice($groupText, isTop: true);   // 异步群通知
+        }
+    }
 }

+ 0 - 10
app/Services/BaseService.php

@@ -387,16 +387,6 @@ class BaseService
                         $btn['callback_data'] = $button['url'];
                     }
                     $inlineButton[count($inlineButton) - 1][] = $btn;
-                    // if (isset($button['text'])) {
-                    //     $btn = ['text' => $button['text']];
-                    //     if (isset($button['callback_data'])) {
-                    //         $btn['callback_data'] = $button['callback_data'];
-                    //     }
-                    //     if (isset($button['url'])) {
-                    //         $btn['url'] = $button['url'];
-                    //     }
-                    //     $inlineButton[count($inlineButton) - 1][] = $btn;
-                    // }
                 }
             }
             $inlineButton = array_values($inlineButton);

+ 73 - 210
app/Services/BetService.php

@@ -249,9 +249,22 @@ class BetService extends BaseService
         }
 
         // 期数验证
-        $issueInfo = IssueService::model()::where('status', IssueService::model()::STATUS_BETTING)->orderBy('id', 'desc')->first();
+
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+        if ($pc28Switch == 1) {
+            $issueInfo = PcIssue::where('status', PcIssue::STATUS_BETTING)->orderBy('id', 'desc')->first();
+        } else {
+            $issueInfo = IssueService::model()::where('status', IssueService::model()::STATUS_BETTING)->orderBy('id', 'desc')->first();
+        }
+
         if (empty($issueInfo)) {
-            $issueCloseInfo = IssueService::model()::where('status', IssueService::model()::STATUS_CLOSE)->orderBy('id', 'desc')->first();
+            if ($pc28Switch == 1) {
+                $issueCloseInfo = PcIssue::where('status', PcIssue::STATUS_CLOSE)->orderBy('id', 'desc')->first();
+            } else {
+                $issueCloseInfo = IssueService::model()::where('status', IssueService::model()::STATUS_CLOSE)->orderBy('id', 'desc')->first();
+            }
+
+
             if (empty($issueCloseInfo)) {
                 $errText .= lang("暂无可下注期数,本次下注无效!");
                 return false;
@@ -342,13 +355,17 @@ class BetService extends BaseService
         $lastStr = self::hideMiddleDigits($userInfo->member_id, 4);
 
         $issueNo = $issueInfo->issue_no;
+
+        $lang = App::getLocale();
+        $group_language = Config::where('field', 'group_language')->first()->val;
+        App::setLocale($group_language);
         $groupText = lang("会员下注") . " 【" . $lastStr . "】 \n";
         $groupText .= lang('下注期数') . ":{$issueInfo->issue_no} \n";
         $groupText .= lang("下注内容") . ": \n";
         $groupText .= "----------- \n";
         $groupText .= "{$keywords}{$amount} \n";
         $groupText .= "----------- \n";
-
+        App::setLocale($lang);
 
         $inlineButton = self::getOperateButton();
 
@@ -358,9 +375,20 @@ class BetService extends BaseService
         return true;
     }
 
+    //随机虚拟下注
+    public static function randomVirtualBetting($maxPeople = 1): void
+    {
+        $maxPeople = intval($maxPeople);
+        $maxPeople = max($maxPeople, 1);
+        $maxPeople = min($maxPeople, 20);
+        $num = rand(1, $maxPeople);
+        for ($i = 0; $i < $num; $i++) {
+            static::fakeBet();
+        }
+    }
 
     // 模拟下注
-    public static function fakeBet()
+    private static function fakeBet()
     {
         $noRule = ['0操', '27操'];
         // 防止一开就虚拟投注
@@ -377,13 +405,12 @@ class BetService extends BaseService
         $betFake = Config::where('field', 'bet_fake')->first()->val;
         if ($betFake) {
             // 期数验证
-
-//            $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
-//            if ($pc28Switch == 1) {
-//                $issueInfo = PcIssue::where('status', IssueService::model()::STATUS_BETTING)->orderBy('id', 'desc')->first();
-//            } else {
-//              }
-            $issueInfo = IssueService::model()::where('status', IssueService::model()::STATUS_BETTING)->orderBy('id', 'desc')->first();
+            $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+            if ($pc28Switch == 1) {
+                $issueInfo = PcIssue::where('status', PcIssue::STATUS_BETTING)->orderBy('id', 'desc')->first();
+            } else {
+                $issueInfo = IssueService::model()::where('status', IssueService::model()::STATUS_BETTING)->orderBy('id', 'desc')->first();
+            }
 
             if ($issueInfo) {
                 $betFakeRandAmount = Config::where('field', 'bet_fake_rand_amount')->first()->val;
@@ -439,15 +466,16 @@ class BetService extends BaseService
                             $fake_bet_list[] = $item;
 
                             $lastStr = self::hideMiddleDigits($item['member_id'], 4);
-
-                            $groupText = "";
-                            $groupText .= "会员下注 【" . $lastStr . "】 \n";
-                            $groupText .= "下注期数:{$issueInfo->issue_no} \n";
-                            $groupText .= "下注内容: \n";
+                            $lang = App::getLocale();
+                            $group_language = Config::where('field', 'group_language')->first()->val;
+                            App::setLocale($group_language);
+                            $groupText = lang('会员下注') . " 【" . $lastStr . "】 \n";
+                            $groupText .= lang('下注期数') . ":{$issueInfo->issue_no} \n";
+                            $groupText .= lang('下注内容') . ": \n";
                             $groupText .= "----------- \n";
                             $groupText .= "{$input} \n";
                             $groupText .= "----------- \n";
-
+                            App::setLocale($lang);
 
                             if (strtotime($issueInfo['end_time']) - strtotime($now_date) < 22) {
                                 $fake_bet_count = Cache::get("fake_bet_count_{$issueInfo->issue_no}", 0);
@@ -458,7 +486,6 @@ class BetService extends BaseService
                             $inlineButton = self::getOperateButton();
 
                             // 群通知
-                            // self::bettingGroupNotice($groupText, $inlineButton);   // 群通知
                             self::asyncBettingGroupNotice($groupText, $inlineButton);   // 异步群通知
                         }
                     }
@@ -838,168 +865,6 @@ class BetService extends BaseService
         self::lotteryNotice($openList, $issue_no, $keywordsList);
     }
 
-    /**
-     * @description: 中奖结算
-     * @param {*} $issue_no
-     * @param {*} $awards
-     * @return {*}
-     */
-    public static function betSettled2($issue_no, $awards)
-    {
-        $list = self::findAll(['issue_no' => $issue_no, 'status' => self::model()::STATUS_STAY]);
-
-        $data = [];
-        $text = $issue_no . "期开奖结果 \n";
-        $text .= "-----本期开奖账单----- \n";
-        // $text .=" 中奖类型 用户 投注金额 中奖金额 盈亏 \n";
-        $text .= "\n";
-        $betNoticeNum = Config::where('field', 'bet_notice_num')->first()->val;
-        $betNoticeNum = explode(',', $betNoticeNum);
-        $betNoticeMini = $betNoticeNum[0] ?? 26;
-        $betNoticeMax = $betNoticeNum[1] ?? 38;
-        $noticeNum = rand($betNoticeMini, $betNoticeMax);
-
-        $realNoticeNum = ceil($noticeNum / 2);
-        $openList = [];
-        $bet_num = 0;
-        foreach ($list->toArray() as $k => $v) {
-            // $userInfo = UserService::findAll(['member_id' => $v['member_id']]);
-            // $lastStr = self::getLastChar($userInfo->first_name, 1);
-            $lastStr = self::hideMiddleDigits($v['member_id'], 4);
-            $item = [];
-            $item['id'] = $v['id'];
-            $item['status'] = self::model()::STATUS_SETTLED;
-
-
-            if (in_array($v['keywords'], $awards)) {
-                // $profit = $v['amount'] * $v['odds'];
-                $amount = $v['amount'];
-                // $amount = rtrim($amount, '0');   // 去掉右侧的 0
-                // $amount = rtrim($amount, '.');   // 如果末尾是 . 就去掉
-                $odds = $v['odds'];
-                $profit = bcmul($amount, $odds, 2); // 保留两位小数
-                if ($profit > 880000) {
-                    $profit = 880000; // 单注最高奖金880000
-                }
-                $item['profit'] = $profit;
-
-                // $yl = $profit - $amount;
-                $yl = bcsub($profit, $amount, 2); // 盈利
-                // if ($k + 1 <= $realNoticeNum) {
-
-                //     // $text .= "会员下注 【" . $lastStr . "】{$v['amount']} {$profit} {$yl}\n";
-                //     $bet_num++;
-                // }
-                // 结算
-                // WalletService::updateBalance($v['member_id'], $profit);
-
-                // $walletInfo = WalletService::findOne(['member_id' => $v['member_id']]);
-                // $balance = $walletInfo['available_balance'];
-
-                // BalanceLogService::addLog($v['member_id'], $profit, $balance, ($balance + $profit), '中奖', $v['id'], '');
-
-                if (isset($openList[$v['member_id']])) {
-                    $openList[$v['member_id']]['member_id'] = $v['member_id'];
-                    $openList[$v['member_id']]['amount'] += $v['amount'];
-                    $openList[$v['member_id']]['profit'] += $profit;
-                    $openList[$v['member_id']]['lastStr'] = $lastStr;
-                    $openList[$v['member_id']]['openKeywords'][] = $v['keywords'];
-                    $openList[$v['member_id']]['keywords'][] = $v['keywords'];
-                    $openList[$v['member_id']]['win_amount'] += $v['amount'];
-
-                } else {
-                    $openList[$v['member_id']]['member_id'] = $v['member_id'];
-                    $openList[$v['member_id']]['amount'] = $v['amount'];
-                    $openList[$v['member_id']]['profit'] = $profit;
-                    $openList[$v['member_id']]['lastStr'] = $lastStr;
-                    $openList[$v['member_id']]['openKeywords'] = [];
-                    $openList[$v['member_id']]['keywords'] = [];
-                    $openList[$v['member_id']]['openKeywords'][] = $v['keywords'];
-                    $openList[$v['member_id']]['keywords'][] = $v['keywords'];
-                    $openList[$v['member_id']]['win_amount'] = $v['amount'];
-                    $openList[$v['member_id']]['is_send'] = true;
-
-                }
-            } else {
-
-                if (isset($openList[$v['member_id']])) {
-                    $openList[$v['member_id']]['member_id'] = $v['member_id'];
-                    $openList[$v['member_id']]['amount'] += $v['amount'];
-                    $openList[$v['member_id']]['lastStr'] = $lastStr;
-                    $openList[$v['member_id']]['keywords'][] = $v['keywords'];
-                } else {
-                    $openList[$v['member_id']]['member_id'] = $v['member_id'];
-                    $openList[$v['member_id']]['amount'] = $v['amount'];
-                    $openList[$v['member_id']]['profit'] = 0;
-                    $openList[$v['member_id']]['lastStr'] = $lastStr;
-                    $openList[$v['member_id']]['openKeywords'] = [];
-                    $openList[$v['member_id']]['keywords'] = [];
-                    $openList[$v['member_id']]['keywords'][] = $v['keywords'];
-                    $openList[$v['member_id']]['win_amount'] = 0;
-                    $openList[$v['member_id']]['is_send'] = true;
-                }
-
-
-                // if ($k + 1 <= $realNoticeNum) {
-                //     // $text .= "会员下注 【" . $lastStr . "】{$v['amount']} {$v['profit']} -{$v['amount']}\n";
-                //     $bet_num++;
-                // }
-            }
-
-            // self::model()::where('id', $v['id'])->update($item);
-        }
-
-        // foreach($openList as $k => $v){
-        //     $amount = $v['amount'];
-        //     // if($v['profit'] >= 0){
-        //         $profit = number_format($v['profit'],2);
-        //         $yl = bcsub($v['profit'], $v['amount'], 2); // 盈利
-        //         // $text .= "会员下注 【" . $v['lastStr'] . "】 {$amount} {$profit} {$yl}\n";
-        //         if(++$bet_num <= $realNoticeNum){
-        //             $text .= "用户ID:{$v['lastStr']} \n";
-        //             $text .= "下注类型:[".implode(',', $v['keywords'])."] \n";
-        //             $text .= "中奖类型:[".implode(',', $v['openKeywords'])."] \n";
-        //             $text .= "投注金额:{$amount} \n";
-        //             $text .= "中奖金额:{$v['win_amount']} \n";
-        //             $text .= "派彩金额:{$profit} \n";
-        //             $text .= "盈亏金额:{$yl} \n";
-        //             $text .= "-------------------------------- \n";
-        //         }
-
-
-        //         $text2 = "{$issue_no}期开奖结果 \n";
-        //         $text2 .= "下注类型:[".implode(',', $v['keywords'])."] \n";
-        //         $text2 .= "中奖类型:[".implode(',', $v['openKeywords'])."] \n";
-        //         $text2 .= "投注金额:{$amount} \n";
-        //         $text2 .= "中奖金额:{$v['win_amount']} \n";
-        //         $text2 .= "派彩金额:{$profit} \n";
-        //         $text2 .= "盈亏金额:{$yl} \n";
-        //         $keyboard = [];
-        //         $keyboard[] = [
-        //             ['text' => "开奖历史", 'callback_data' => "showLotteryHistory@@" . $issue_no]
-        //         ];
-        //         // SendTelegramMessageJob::dispatch($v['member_id'],$text2);
-        //         self::sendMessage($v['member_id'],$text2,$keyboard);
-        //     // }else{
-        //     //     $text .= "会员下注 【" . $v['lastStr'] . "】 {$amount} 0 -{$amount}\n";
-        //     // }
-
-
-        // }
-
-        $inlineButton = self::getOperateButton();
-
-        $rand_num = $noticeNum - $bet_num;
-        $fakeOpenData = self::fakeLotteryDraw($issue_no, $awards, $rand_num);
-        $openList = array_merge($openList, $fakeOpenData['list']);
-
-        // 群通知
-        // self::bettingGroupNotice($text, $inlineButton, '');
-        // SendTelegramGroupMessageJob::dispatch($text,$inlineButton,'');
-        self::lotteryNotice($openList, $issue_no);
-    }
-
-
     // 虚拟开奖
     public static function fakeLotteryDraw($issue_no, $awards, $rand_num = 30)
     {
@@ -1095,9 +960,12 @@ class BetService extends BaseService
         // shuffle($openList);
         // Log::error('lotteryNotice openList', $openList);
 
-
-        $text = "{$issue_no}期开奖结果";
-        $text .= "\n-----本期开奖账单----- \n";
+        $lang = App::getLocale();
+        $group_language = Config::where('field', 'group_language')->first()->val;
+        App::setLocale($group_language);
+        $text = "{$issue_no}" . lang("期开奖结果");
+        $text .= "\n-----" . lang("本期开奖账单") . "----- \n";
+        App::setLocale($lang);
         foreach ($openList as $k => $v) {
 
 
@@ -1113,14 +981,18 @@ class BetService extends BaseService
             }
 
             if (($k + 1) <= $noticeNum) {
-                $text .= "用户ID:{$v['lastStr']} \n";
-                $text .= "下注类型:[" . implode(',', $v['keywords']) . "] \n";
-                $text .= "中奖类型:[" . $openKeyword . "] \n";
-                $text .= "投注金额:{$amount} \n";
-                $text .= "中奖金额:{$v['win_amount']} \n";
-                $text .= "派彩金额:{$profit} \n";
-                $text .= "盈亏金额:{$yl} \n";
+                $lang = App::getLocale();
+                $group_language = Config::where('field', 'group_language')->first()->val;
+                App::setLocale($group_language);
+                $text .= lang("用户ID") . ":{$v['lastStr']} \n";
+                $text .= lang("下注类型") . ":[" . implode(',', $v['keywords']) . "] \n";
+                $text .= lang('中奖类型') . ":[" . $openKeyword . "] \n";
+                $text .= lang('投注金额') . ":{$amount} \n";
+                $text .= lang('中奖金额') . ":{$v['win_amount']} \n";
+                $text .= lang('派彩金额') . ":{$profit} \n";
+                $text .= lang("盈亏金额") . ":{$yl} \n";
                 $text .= "-------------------------------- \n";
+                App::setLocale($lang);
             }
 
             if ($v['is_send']) {
@@ -1146,21 +1018,11 @@ class BetService extends BaseService
         }
 
         $inlineButton = self::getOperateButton();
-
-
         // 群通知
-        // self::bettingGroupNotice($text, $inlineButton, '');
-
-        // Log::error('lotteryNotice Group:'.$text);
-
-//        $pos = strrpos($text, '--------------------------------');
-//
-//        if ($pos !== false) {
-//            // 使用 substr_replace 来删除最后一个 "ne"
-//            $text = substr_replace($text, "", $pos, strlen('--------------------------------'));
-//        }
-
-        SendTelegramGroupMessageJob::dispatch($text, $inlineButton, '', false, '--------------------------------');
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+        if (($pc28Switch == 0 && is_numeric($issue_no)) || $pc28Switch == 1 && !is_numeric($issue_no)) {
+            SendTelegramGroupMessageJob::dispatch($text, $inlineButton, '', false, '--------------------------------');
+        }
 
 
     }
@@ -1192,20 +1054,21 @@ class BetService extends BaseService
                 $keywordsList[$v['keywords']] = $v['amount'];
             }
         }
-
-        $text3 = "📝 {$issue_no}期投注统计 \n";
-        $text3 .= "玩法    总投 \n";
+        $lang = App::getLocale();
+        $group_language = Config::where('field', 'group_language')->first()->val;
+        App::setLocale($group_language);
+        $text3 = "📝 {$issue_no}" . lang('期投注统计') . " \n";
+        $text3 .= lang("玩法") . "    " . lang("总投") . " \n";
 
         if ($keywordsList) {
             ksort($keywordsList);
             foreach ($keywordsList as $k => $v) {
                 $text3 .= "{$k}    {$v} \n";
-                // $text3 .= "玩法:{$k} \n";
-                // $text3 .= "总注:{$v} \n";
-                // $text3 .= "-------------- \n";
             }
         }
+        App::setLocale($lang);
         $inlineButton = self::getOperateButton();
+
         SendTelegramGroupMessageJob::dispatch($text3, $inlineButton, '');
     }
 

+ 42 - 44
app/Services/IssueService.php

@@ -5,6 +5,7 @@ namespace App\Services;
 
 use App\Models\Cao;
 use App\Models\CaoHistory;
+use App\Models\PcIssue;
 use App\Models\Prediction;
 use App\Services\BaseService;
 use App\Models\Issue;
@@ -63,9 +64,9 @@ class IssueService extends BaseService
         if (isset($search['status']) && !empty($search['status'])) {
             $where[] = ['status', '=', $search['status']];
         }
-        if(isset($search['abnormal']) && !empty($search['abnormal'])){
-            $where[] = ['end_time' ,'<' ,date('Y-m-d H:i:s',time() - 1800)];
-            $where[] = ['status' ,'!=' ,self::model()::STATUS_DRAW];
+        if (isset($search['abnormal']) && !empty($search['abnormal'])) {
+            $where[] = ['end_time', '<', date('Y-m-d H:i:s', time() - 1800)];
+            $where[] = ['status', '!=', self::model()::STATUS_DRAW];
         }
         return $where;
     }
@@ -160,9 +161,8 @@ class IssueService extends BaseService
         $info->status = self::model()::STATUS_BETTING;
         $info->save();
 
-        // $text = "";
-        // $text .= "第".$info->issue_no."期\n";
-        // $text .= "🔥🔥🔥🔥🔥开始下注🔥🔥🔥🔥🔥\n";
+
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
         $replyInfo = KeyboardService::findOne(['button' => '玩法规则']);
         if ($replyInfo) {
             $text = $replyInfo->reply;
@@ -174,7 +174,8 @@ class IssueService extends BaseService
             if (empty($buttons)) {
                 $buttons = self::getOperateButton();
             }
-            self::asyncBettingGroupNotice($text, $buttons, $image);
+
+            if ($pc28Switch == 0) self::asyncBettingGroupNotice($text, $buttons, $image);
         }
 
         $replyInfo = KeyboardService::findOne(['button' => '开始下注']);
@@ -185,7 +186,7 @@ class IssueService extends BaseService
             if ($image) {
                 $image = url($image);
             }
-            self::asyncBettingGroupNotice($text, $buttons, $image);
+            if ($pc28Switch == 0) self::asyncBettingGroupNotice($text, $buttons, $image);
         }
 
         return ['code' => self::YES, 'msg' => '开始下注'];
@@ -206,7 +207,7 @@ class IssueService extends BaseService
         if ($info->status != self::model()::STATUS_BETTING) {
             return ['code' => self::NOT, 'msg' => '期号状态不正确'];
         }
-
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
         $info->status = self::model()::STATUS_CLOSE;
         $info->save();
         $replyInfo = KeyboardService::findOne(['button' => '停止下注']);
@@ -217,12 +218,12 @@ class IssueService extends BaseService
             if ($image) {
                 $image = url($image);
             }
-            // self::bettingGroupNotice($text, $buttons, $image);
-            self::asyncBettingGroupNotice($text, $buttons, $image);
+            if ($pc28Switch == 0) self::asyncBettingGroupNotice($text, $buttons, $image);
         }
 
         // 投注情况通知
-        BetService::statNotice($info->issue_no);
+        if ($pc28Switch == 0) BetService::statNotice($info->issue_no);
+
 
         $replyInfo = KeyboardService::findOne(['button' => '封盘开奖']);
         if ($replyInfo) {
@@ -233,10 +234,9 @@ class IssueService extends BaseService
                 $image = url($image);
             }
             // self::bettingGroupNotice($text, $buttons, $image);
-            self::asyncBettingGroupNotice($text, $buttons, $image);
+            if ($pc28Switch == 0) self::asyncBettingGroupNotice($text, $buttons, $image);
         }
 
-        
 
         return ['code' => self::YES, 'msg' => '封盘成功'];
     }
@@ -245,7 +245,7 @@ class IssueService extends BaseService
      * @description: 开奖失败
      * @param {*} $id
      * @return {*}
-     */    
+     */
     public static function lotteryDrawFail($id)
     {
 
@@ -272,7 +272,6 @@ class IssueService extends BaseService
             DB::rollBack();
             return ['code' => self::NOT, 'msg' => '投注退回失败'];
         }
-        
 
 
         if ($result) {
@@ -323,12 +322,12 @@ class IssueService extends BaseService
             Cao::updateData($awards);
             CaoHistory::updateData($awards);
 
-
+            $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
             $replyInfo = KeyboardService::findOne(['button' => '本期开奖']);
             if ($replyInfo) {
                 $text = $replyInfo->reply;
                 $text .= "\n";
-                $text .= $info->issue_no . " " . implode('+', explode(',', $winning_numbers)) . "=" . array_sum($winArr) . " " . $combo;
+                $text .= $info->issue_no . " " . implode('+', explode(',', $winning_numbers)) . "=" . array_sum($winArr) . " " . $combo;
 
                 $buttons = json_decode($replyInfo->buttons, true);
                 $image = $replyInfo->image;
@@ -337,20 +336,17 @@ class IssueService extends BaseService
                 }
                 if (empty($buttons)) {
                     $serviceAccount = Config::where('field', 'service_account')->first()->val;
-                    $buttons[] = [['text' => '✅唯一财务', 'callback_data' => "", 'url' => "https://t.me/{$serviceAccount}"]];
+                    $buttons[] = [['text' => lang('✅唯一财务'), 'callback_data' => "", 'url' => "https://t.me/{$serviceAccount}"]];
 
                 }
                 // self::bettingGroupNotice($text, $buttons, $image, true);
-                SendTelegramGroupMessageJob::dispatch($text, $buttons, $image, true);
+                if ($pc28Switch == 0) SendTelegramGroupMessageJob::dispatch($text, $buttons, $image, true);
             }
 
-            if (config('app.url') != 'https://botpc28.testx2.cc') {
-                $recordImage = self::lotteryImage($info->issue_no);
-
-            }
+            $recordImage = self::lotteryImage($info->issue_no);
             if ($recordImage) {
                 // self::bettingGroupNotice('', [], url($recordImage));
-                SendTelegramGroupMessageJob::dispatch('', [], url($recordImage), false);
+                if ($pc28Switch == 0) SendTelegramGroupMessageJob::dispatch('', [], url($recordImage), false);
             }
 
 
@@ -750,11 +746,11 @@ class IssueService extends BaseService
                 //     'text' => lang("暂无开奖记录"),
                 // ]);
                 // }
-                return 
-                [
-                    'chat_id' => $memberId,
-                    'text' => lang("暂无开奖记录"),
-                ];
+                return
+                    [
+                        'chat_id' => $memberId,
+                        'text' => lang("暂无开奖记录"),
+                    ];
 
             }
 
@@ -802,18 +798,17 @@ class IssueService extends BaseService
 
                 $combo = [];
 
-                $sumOddEven = self::calculateOddEven($sum); // 总和单双
-                $combo[] = $sumOddEven;
-
                 $sumSize = self::calculateSumSize($sum);  // 总和大小
                 $combo[] = $sumSize;
 
+                $sumOddEven = self::calculateOddEven($sum); // 总和单双
+                $combo[] = $sumOddEven;
+
                 $sumExtremeSize = self::calculateSumExtremeSize($sum);  // 总和极值
                 if ($sumExtremeSize) {
                     $combo[] = $sumExtremeSize;
                 }
 
-
                 $sumBaoZi = self::isBaoZi($winArr[0], $winArr[1], $winArr[2]); // 豹子
                 if ($sumBaoZi) {
                     $combo[] = $sumBaoZi;
@@ -841,10 +836,9 @@ class IssueService extends BaseService
                     self::lotteryDraw($v->id, $winning_numbers, $combo, '');
                     $new = false;
                 }
-
-                // Log::error('开奖缓存: ' .$key);
-                // Log::error('开奖缓存结果: ' .($new ? '新开奖' : '已开奖') );
-
+                $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+                //更新游戏开关的切换
+                if ($pc28Switch == 0) Config::setPc28Switch();
             }
         }
 
@@ -873,6 +867,7 @@ class IssueService extends BaseService
                 $id = $res['key'] ?? 0;
                 if ($id) {
                     self::betting($id); // 开始下注
+
                 }
                 Cache::set('new_issue_no', $new_issue_no, 10); // 缓存
             }
@@ -969,25 +964,28 @@ class IssueService extends BaseService
     // 封盘倒数
     public static function syncCountdownIssue()
     {
-        $now_date = date('Y-m-d H:i:s', time() + 60); // 提前60秒
-        $info = self::model()::where('status', self::model()::STATUS_BETTING)->orderBy('end_time', 'asc')->first();
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+        if ($pc28Switch == 1) {
+            $info = PcIssue::where('status', PcIssue::STATUS_BETTING)->orderBy('end_time')->first();
+        } else {
+            $info = self::model()::where('status', self::model()::STATUS_BETTING)->orderBy('end_time', 'asc')->first();
+        }
         if ($info) {
+            $now_date = date('Y-m-d H:i:s', time() + 60); // 提前60秒
             if ($info['end_time'] < $now_date) {
                 $replyInfo = KeyboardService::findOne(['button' => '封盘倒数']);
                 if ($replyInfo) {
-
                     $text = $replyInfo->reply;
                     $buttons = json_decode($replyInfo->buttons, true);
                     $image = $replyInfo->image;
                     if ($image) {
                         $image = url($image);
                     }
-                    if (Cache::has('issue_countdown_' . $info->id)) {
+                    if (Cache::has('issue_countdown_' . $info->issue_no)) {
 
                     } else {
-                        // self::bettingGroupNotice($text, $buttons, $image);
                         self::asyncBettingGroupNotice($text, $buttons, $image);
-                        Cache::put('issue_countdown_' . $info->id, true, 60); // 缓存50秒,防止多次发送
+                        Cache::put('issue_countdown_' . $info->issue_no, true, 60); // 缓存50秒,防止多次发送
                     }
 
                 }

+ 8 - 5
app/Services/LotteryImageService.php

@@ -2,6 +2,8 @@
 
 namespace App\Services;
 
+use App\Models\Config;
+use Illuminate\Support\Facades\App;
 use Illuminate\Support\Facades\Storage;
 
 class LotteryImageService
@@ -18,8 +20,9 @@ class LotteryImageService
         $html = $this->buildHtml($records);
 
         // ========= 2. 保存HTML到临时文件 =========
-        $htmlPath = storage_path('app/lottery_temp.html');
-        $htmlPath = base_path()."/public/static/html/lottery_temp.html";
+        //        $htmlPath = storage_path("app/lottery_temp.html");
+        $group_language = Config::where('field', 'group_language')->first()->val;
+        $htmlPath = base_path()."/public/static/html/lottery_temp_{$group_language}.html";
         file_put_contents($htmlPath, $html);
 
         // ========= 3. 输出图片路径 =========
@@ -52,7 +55,7 @@ class LotteryImageService
      */
     protected function buildHtml($records): string
     {
-       
+
         $rows = '';
         foreach ($records as $row) {
             $rows .= '<tr>';
@@ -70,8 +73,8 @@ class LotteryImageService
             }
             $rows .= ' = ' . array_sum($row['winning_numbers']) . '</td>';
             $rows .= '<td>' . $row['combo'] . '</td>';
-            $rows .= '<td>'.$row['extreme'].'</td>';
-            $rows .= '<td>'.$row['tail'].'</td>';
+            $rows .= '<td>' . $row['extreme'] . '</td>';
+            $rows .= '<td>' . $row['tail'] . '</td>';
             $rows .= '</tr>';
         }
 

+ 227 - 8
app/Services/PcIssueService.php

@@ -2,10 +2,15 @@
 
 namespace App\Services;
 
+use App\Jobs\SendTelegramGroupMessageJob;
+use App\Models\Config;
 use App\Models\PcCao;
 use App\Models\PcCaoHistory;
 use App\Models\PcIssue;
 use App\Models\PcPrediction;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
 
 class PcIssueService extends BaseService
 {
@@ -26,31 +31,102 @@ class PcIssueService extends BaseService
 
     private static function fengPan()
     {
-        $list = PcIssue::where('status', PcIssue::STATUS_BETTING)->get();
+        $list = PcIssue::where('status', PcIssue::STATUS_BETTING)
+            ->orderByDesc('id')
+            ->get();
         $now = time();
-        foreach ($list as $item) {
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+
+
+        foreach ($list as $index => $item) {
             if (strtotime($item->end_time) - 30 <= $now) {
                 $item->status = PcIssue::STATUS_CLOSE;
                 $item->save();
+
+                if ($index == 0 && $pc28Switch == 1) {
+                    $replyInfo = KeyboardService::findOne(['button' => '停止下注']);
+                    if ($replyInfo) {
+                        $text = $replyInfo->reply;
+                        $buttons = json_decode($replyInfo->buttons, true);
+                        $image = $replyInfo->image;
+                        if ($image) $image = url($image);
+                        self::asyncBettingGroupNotice($text, $buttons, $image);
+                    }
+
+                    // 统计投注情况通知
+                    BetService::statNotice($item->issue_no);
+                    $replyInfo = KeyboardService::findOne(['button' => '封盘开奖']);
+                    if ($replyInfo) {
+                        $text = $replyInfo->reply;
+                        $buttons = json_decode($replyInfo->buttons, true);
+                        $image = $replyInfo->image;
+                        if ($image) $image = url($image);
+                        self::asyncBettingGroupNotice($text, $buttons, $image);
+                    }
+                }
+
+
             }
         }
     }
 
-
     private static function kaiJiang(): void
     {
-        $list = PcIssue::where('status', PcIssue::STATUS_CLOSE)->get();
+        $list = PcIssue::where('status', PcIssue::STATUS_CLOSE)
+            ->orderByDesc('id')->get();
         $now = time();
-        foreach ($list as $item) {
+        foreach ($list as $index => $item) {
             if (strtotime($item->end_time) <= $now) {
                 $keno = static::getKeno();
                 $item->keno = json_encode($keno);
                 $winningNumbers = static::getWinningNumbers($keno);
                 $item->winning_numbers = implode(',', $winningNumbers);
-                $item->status = PcIssue::STATUS_DRAW;
                 $item->save();
-                $awards = IssueService::award(explode(',', $item->winning_numbers));
 
+
+                $winArr = array_map('intval', $winningNumbers);
+                // 组合
+                $sum = array_sum($winArr);
+                $combo = [];
+                $sumSize = IssueService::calculateSumSize($sum);  // 总和大小
+                $combo[] = $sumSize;
+
+                $sumOddEven = IssueService::calculateOddEven($sum); // 总和单双
+                $combo[] = $sumOddEven;
+                $sumExtremeSize = IssueService::calculateSumExtremeSize($sum);  // 总和极值
+                if ($sumExtremeSize) {
+                    $combo[] = $sumExtremeSize;
+                }
+                $sumBaoZi = IssueService::isBaoZi($winArr[0], $winArr[1], $winArr[2]); // 豹子
+                if ($sumBaoZi) {
+                    $combo[] = $sumBaoZi;
+                }
+                $sumPair = IssueService::isPair($winArr[0], $winArr[1], $winArr[2]); // 对子
+                if ($sumPair) {
+                    $combo[] = $sumPair;
+                }
+                $sumStraight = IssueService::isStraight($winArr[0], $winArr[1], $winArr[2]); // 顺子
+                if ($sumStraight) {
+                    $combo[] = $sumStraight;
+                }
+                $tail = IssueService::getLastDigit($sum); // 总和尾数
+                if ($tail != 0 && $tail != 9) {
+                    $combo[] = '尾' . $tail; // 尾数
+                }
+
+
+                $key = 'lottery_numbers_' . $item->issue_no;
+                $combo = implode(' ', $combo);
+
+                if (Cache::add($key, $item->winning_numbers, 100)) {
+                    self::lotteryDraw($item->issue_no, $item->winning_numbers, $combo, '');
+                }
+
+                $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+                //更新游戏开关的切换
+                if ($pc28Switch == 1) Config::setPc28Switch();
+
+                $awards = IssueService::award(explode(',', $item->winning_numbers));
                 //预测结果
                 PcPrediction::result($item->issue_no, $item->winning_numbers, $awards);
                 //自开奖以来的结果统计
@@ -63,6 +139,107 @@ class PcIssueService extends BaseService
         }
     }
 
+    //开奖
+    private static function lotteryDraw($issue_no, $winning_numbers, $combo, $recordImage)
+    {
+        $info = PcIssue::where('issue_no', $issue_no)->first();
+        if (!$info) {
+            return ['code' => self::NOT, 'msg' => '期号不存在'];
+        }
+        if ($info->status == PcIssue::STATUS_DRAW) {
+            return ['code' => self::NOT, 'msg' => '期号状态不正确'];
+        }
+
+        $winArr = array_map('intval', explode(',', $winning_numbers));
+        // 计算中奖
+        $awards = IssueService::award(explode(',', $winning_numbers));
+        DB::beginTransaction();
+        try {
+            $info->status = PcIssue::STATUS_DRAW;
+            $info->combo = $combo;
+            $info->image = $recordImage;
+            $info->save();
+
+
+            $replyInfo = KeyboardService::findOne(['button' => '本期开奖']);
+
+            if ($replyInfo) {
+                $text = $replyInfo->reply;
+                $text .= "\n";
+                $text .= $info->issue_no . ": " . implode('+', explode(',', $winning_numbers)) . "=" . array_sum($winArr) . " " . $combo;
+
+                $buttons = json_decode($replyInfo->buttons, true);
+                $image = $replyInfo->image;
+                if ($image) {
+                    $image = url($image);
+                }
+                if (empty($buttons)) {
+                    $serviceAccount = Config::where('field', 'service_account')->first()->val;
+                    $buttons[] = [['text' => lang('✅唯一财务'), 'callback_data' => "", 'url' => "https://t.me/{$serviceAccount}"]];
+
+                }
+                SendTelegramGroupMessageJob::dispatch($text, $buttons, $image, true);
+            }
+
+            $recordImage = self::lotteryImage($info->issue_no);
+            if ($recordImage) {
+                SendTelegramGroupMessageJob::dispatch('', [], url($recordImage), false);
+            }
+            BetService::betSettled($info->issue_no, $awards);
+            DB::commit();
+            return ['code' => self::YES, 'msg' => '开奖成功'];
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('开奖失败: ' . $e->getMessage() . $winning_numbers);
+            return ['code' => self::NOT, 'msg' => '开奖失败'];
+        }
+    }
+
+
+    // 生成开奖图片
+    private static function lotteryImage($issue_no)
+    {
+        $list = PcIssue::where('issue_no', '<=', $issue_no)->where('status', PcIssue::STATUS_DRAW)->orderBy('issue_no', 'desc')->take(20)->get();
+        $records = $list->toArray();
+
+        foreach ($records as $k => $v) {
+            $winning_numbers = explode(',', $v['winning_numbers']);
+            $v['winning_numbers'] = $winning_numbers;
+
+            // 组合
+            $sum = array_sum($winning_numbers);
+
+            $v['sum'] = $sum;
+            $sumOddEven = IssueService::calculateOddEven($sum); // 总和单双
+
+            $sumSize = IssueService::calculateSumSize($sum);  // 总和大小
+            $v['combo'] = $sumSize . ' ' . $sumOddEven;
+
+            $sumExtremeSize = IssueService::calculateSumExtremeSize($sum);  // 总和极值
+            if (!$sumExtremeSize) {
+                $sumExtremeSize = '-';
+            }
+            $v['extreme'] = $sumExtremeSize;
+
+            $tail = IssueService::getLastDigit($sum); // 总和尾数
+            if ($tail === 0 || $tail === 9) {
+                $tailStr = '-';
+            } else {
+                $tailStr = '尾' . $tail;
+            }
+            $v['tail'] = $tailStr;
+
+            $records[$k] = $v;
+        }
+        $service = new LotteryImageService();
+        $url = $service->generate($records);
+
+        PcIssue::where('issue_no', $issue_no)->update(['image' => $url]);
+        return $url;
+
+    }
+
+    //创建新的一期
     private static function createIssueNo()
     {
         $issue = PcIssue::orderByDesc('id')->first();
@@ -80,6 +257,7 @@ class PcIssueService extends BaseService
                 'start_time' => $issue->end_time,
                 'end_time' => date('Y-m-d H:i:s', $end_time),
             ]);
+            static::betTing($new_str);
             //预测
             PcPrediction::prediction($new_str);
             if (strtotime($issue->end_time) <= $now) {
@@ -90,6 +268,48 @@ class PcIssueService extends BaseService
 
     }
 
+    //群通知,发送玩法规则和开始下注的通知
+    private static function betTing($issue_no): array
+    {
+        $info = PcIssue::where('issue_no', $issue_no)->first();
+        if (!$info) {
+            return ['code' => self::NOT, 'msg' => '期号不存在'];
+        }
+
+        if (!in_array($info->status, [PcIssue::STATUS_DRAFT, PcIssue::STATUS_BETTING])) {
+            return ['code' => self::NOT, 'msg' => '期号状态不正确'];
+        }
+        $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
+        $info->status = PcIssue::STATUS_BETTING;
+        $info->save();
+        $replyInfo = KeyboardService::findOne(['button' => '玩法规则']);
+        if ($replyInfo) {
+            $text = $replyInfo->reply;
+            $buttons = json_decode($replyInfo->buttons, true);
+            $image = $replyInfo->image;
+            if ($image) {
+                $image = url($image);
+            }
+            if (empty($buttons)) {
+                $buttons = self::getOperateButton();
+            }
+            if ($pc28Switch == 1) self::asyncBettingGroupNotice($text, $buttons, $image);
+        }
+
+        $replyInfo = KeyboardService::findOne(['button' => '开始下注']);
+        if ($replyInfo) {
+            $text = $replyInfo->reply;
+            $buttons = json_decode($replyInfo->buttons, true);
+            $image = $replyInfo->image;
+            if ($image) {
+                $image = url($image);
+            }
+            if ($pc28Switch == 1) self::asyncBettingGroupNotice($text, $buttons, $image);
+        }
+
+        return ['code' => self::YES, 'msg' => '开始下注'];
+    }
+
     //获取随机的20个数字
     private static function getKeno(): array
     {
@@ -113,7 +333,6 @@ class PcIssueService extends BaseService
         return $winningNumbers;
     }
 
-
     //根据指定0-27的数字 得到20个数字
     public static function getMatchingNumbers($target): array|null
     {

+ 1 - 1
database/migrations/2025_12_05_173640_update_config.php

@@ -3,7 +3,7 @@
 use Illuminate\Database\Migrations\Migration;
 use Illuminate\Database\Schema\Blueprint;
 use Illuminate\Support\Facades\Schema;
-
+use Illuminate\Support\Facades\DB;
 return new class extends Migration {
     /**
      * Run the migrations.

+ 29 - 0
database/migrations/2025_12_10_133100_update_config.php

@@ -0,0 +1,29 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        DB::table('config')->where('field', 'pc28_switch')->update(['group_id' => 4]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 37 - 0
database/migrations/2025_12_10_152005_insert_config.php

@@ -0,0 +1,37 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        DB::table('config')->insert([
+            [
+                'field' => 'group_language',
+                'val' => "zh",
+                'remark' => '群消息语言',
+                'group_id' => 1,
+                'created_at' => now(),
+                'updated_at' => now(),
+            ]
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+};

+ 10 - 9
lang/en/messages.php

@@ -290,13 +290,14 @@ return [
     "新用户信息" => "New User Information",
     "管理员已将指定账户转移至您的账户" => "The administrator has transferred the specified account to your account",
     "原账户信息" => "Original Account Information",
-    "比比返失败"=>"The water injection for the DSLR failed",
-    "系统维护中"=>"Under system maintenance",
-     "已超时"=>"Timeout",
-    
+    "已超时" => "Timeout",
+    "比比返失败" => "The water injection for the DSLR failed",
+    "系统维护中" => "Under system maintenance",
+    '✅唯一财务' => '✅Sole finance',
+    "已切换为极速PC28" => "Switched to Speedy PC28",
+    "已切换为加拿大PC28" => "Switched to Canadian PC28",
+    "期投注统计" => "Issue Betting Statistics",
+    "总投" => "Total Bet",
+    "期开奖结果" => "Result of the Draw",
 
-
-
-
-
-];
+    ];

+ 9 - 6
lang/vi/messages.php

@@ -290,12 +290,15 @@ return [
     "新用户信息" => "Thông tin người dùng mới",
     "管理员已将指定账户转移至您的账户" => "Quản trị viên đã chuyển tài khoản được chỉ định sang tài khoản của bạn",
     "原账户信息" => "Thông tin tài khoản cũ",
-    "比比返失败"=>"Máy bơm nước SLR thất bại",
-    "系统维护中"=>"Bảo trì hệ thống",
-     "已超时"=>"Hết giờ",
-
-
-
+    "比比返失败" => "Máy bơm nước SLR thất bại",
+    "系统维护中" => "Bảo trì hệ thống",
+    "已超时" => "Hết giờ",
+    '✅唯一财务' => '✅Tài chính duy nhất',
+    "已切换为极速PC28" => "Đã chuyển sang Speedy PC28",
+    "已切换为加拿大PC28" => "Đã chuyển sang Canadian PC28",
+    "期投注统计" => "Thống kê cược kỳ",
+    "总投" => "Tổng cược",
+    "期开奖结果" => "Kết quả quay số",
 
 
 ];

+ 9 - 4
lang/zh/messages.php

@@ -290,9 +290,14 @@ return [
     "新用户信息" => "新用户信息",
     "管理员已将指定账户转移至您的账户" => "管理员已将指定账户转移至您的账户",
     "原账户信息" => "原账户信息",
-    "比比返失败"=>"比比返失败",
-    "系统维护中"=>"系统维护中",
-    "已超时"=>"已超时",
-
+    "已超时" => "已超时",
+    "比比返失败" => "比比返失败",
+    "系统维护中" => "系统维护中",
+    '✅唯一财务' => '✅唯一财务',
+    "已切换为极速PC28" => "已切换为极速PC28",
+    "已切换为加拿大PC28" => "已切换为加拿大PC28",
+    "期投注统计" => "期投注统计",
+    "总投" => "总投",
+    "期开奖结果" => "期开奖结果",
 
 ];

文件差異過大導致無法顯示
+ 0 - 0
public/doc/assets/main.bundle.js


+ 10 - 10
public/doc/index.html

@@ -10,15 +10,15 @@
     <meta name="description" content="Bot">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <link href="assets/bootstrap.min.css?v=1764313815856" rel="stylesheet" media="screen">
-    <link href="assets/prism.css?v=1764313815856" rel="stylesheet"/>
-    <link href="assets/prism-toolbar.css?v=1764313815856" rel="stylesheet"/>
-    <link href="assets/prism-diff-highlight.css?v=1764313815856" rel="stylesheet"/>
-    <link href="assets/main.css?v=1764313815856" rel="stylesheet" media="screen, print">
-    <link href="assets/favicon.ico?v=1764313815856" rel="icon" type="image/x-icon">
-    <link href="assets/apple-touch-icon.png?v=1764313815856" rel="apple-touch-icon" sizes="180x180">
-    <link href="assets/favicon-32x32.png?v=1764313815856" rel="icon" type="image/png" sizes="32x32">
-    <link href="assets/favicon-16x16.png?v=1764313815856" rel="icon" type="image/png" sizes="16x16">
+    <link href="assets/bootstrap.min.css?v=1765346351988" rel="stylesheet" media="screen">
+    <link href="assets/prism.css?v=1765346351988" rel="stylesheet"/>
+    <link href="assets/prism-toolbar.css?v=1765346351988" rel="stylesheet"/>
+    <link href="assets/prism-diff-highlight.css?v=1765346351988" rel="stylesheet"/>
+    <link href="assets/main.css?v=1765346351988" rel="stylesheet" media="screen, print">
+    <link href="assets/favicon.ico?v=1765346351988" rel="icon" type="image/x-icon">
+    <link href="assets/apple-touch-icon.png?v=1765346351988" rel="apple-touch-icon" sizes="180x180">
+    <link href="assets/favicon-32x32.png?v=1765346351988" rel="icon" type="image/png" sizes="32x32">
+    <link href="assets/favicon-16x16.png?v=1765346351988" rel="icon" type="image/png" sizes="16x16">
     <style>
         body {
             font-family: Arial, sans-serif;
@@ -1599,7 +1599,7 @@
 </div>
 
 
-<script src="assets/main.bundle.js?v=1764313815856"></script>
+<script src="assets/main.bundle.js?v=1765346351988"></script>
 <!--suppress JSJQueryEfficiency, JSStringConcatenationToES6Template, JSStringConcatenationToES6Template, JSStringConcatenationToES6Template -->
 <script>
 

+ 8 - 2
routes/admin.php

@@ -81,7 +81,7 @@ Route::middleware(['admin.jwt'])->group(function () {
             Route::post('/submit', [Issue::class, 'store']);
             Route::post('/betting', [Issue::class, 'betting']);
             Route::post('/close', [Issue::class, 'close']);
-            Route::post('/failure', [Issue::class, 'failure']); 
+            Route::post('/failure', [Issue::class, 'failure']);
             Route::post('/lotteryDraw', [Issue::class, 'lotteryDraw']); // 开奖
             Route::post('/delete', [Issue::class, 'destroy']); // 删除
         });
@@ -118,6 +118,12 @@ Route::middleware(['admin.jwt'])->group(function () {
         });
 
         Route::prefix('/config')->group(function () {
+            Route::get('/pcConfig', [Config::class, 'pcConfig']);
+            Route::post('/pc28Switch', [Config::class, 'pc28Switch']);
+
+
+
+
             Route::get('/getAll', [Config::class, 'getAll']);
             Route::get('/get', [Config::class, 'get']);
             Route::post('/set', [Config::class, 'set']);
@@ -144,7 +150,7 @@ Route::middleware(['admin.jwt'])->group(function () {
         Route::prefix('/user')->group(function () {
             Route::get('/', [User::class, 'index']);
             Route::get('/address', [User::class, 'address']);
-            Route::post('/merge',[User::class, 'merge']);
+            Route::post('/merge', [User::class, 'merge']);
 
 
         });

部分文件因文件數量過多而無法顯示