orderByDesc('id') ->get(); $now = time(); $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) ->orderByDesc('id')->get(); $now = time(); 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->save(); $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, '', $index); } $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); //自开奖以来的结果统计 PcCao::updateData($awards); //每天开奖结果统计 PcCaoHistory::updateData($awards); } } } //开奖 private static function lotteryDraw($issue_no, $winning_numbers, $combo, $recordImage, $index) { $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}"]]; } if ($index == 0) SendTelegramGroupMessageJob::dispatch($text, $buttons, $image, true); } $recordImage = self::lotteryImage($info->issue_no); if ($recordImage) { if ($index == 0) 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(); $now = time(); if (strtotime($issue->end_time) <= $now) { $issue_no = $issue->issue_no; $number = preg_replace('/\D/', '', $issue_no); $number = (int)$number + 1; $new_str = "P" . $number; $end_time = strtotime($issue->end_time) + 210; $status = $end_time - 30 > $now ? PcIssue::STATUS_BETTING : PcIssue::STATUS_CLOSE; $issue = PcIssue::create([ 'issue_no' => $new_str, 'status' => $status, '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) { static::createIssueNo(); } } } //群通知,发送玩法规则和开始下注的通知 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 { $numbers = range(1, 80); shuffle($numbers); $random_numbers = array_slice($numbers, 0, 20); sort($random_numbers); return $random_numbers; } //根据20个数字计算开奖号码 private static function getWinningNumbers($keno): array { $winningNumbers = []; $sum = $keno[1] + $keno[4] + $keno[7] + $keno[10] + $keno[13] + $keno[16]; $winningNumbers[0] = $sum % 10; $sum = $keno[2] + $keno[5] + $keno[8] + $keno[11] + $keno[14] + $keno[17]; $winningNumbers[1] = $sum % 10; $sum = $keno[3] + $keno[6] + $keno[9] + $keno[12] + $keno[15] + $keno[18]; $winningNumbers[2] = $sum % 10; return $winningNumbers; } //根据指定0-27的数字 得到20个数字 public static function getMatchingNumbers($target): array|null { $numbers = range(1, 80); $bestMatch = null; for ($i = 0; $i < 100000; $i++) { shuffle($numbers); $selectedNumbers = array_slice($numbers, 0, 20); sort($selectedNumbers); $firstSum = $selectedNumbers[1] + $selectedNumbers[4] + $selectedNumbers[7] + $selectedNumbers[10] + $selectedNumbers[13] + $selectedNumbers[16]; $firstDigit = $firstSum % 10; $secondSum = $selectedNumbers[2] + $selectedNumbers[5] + $selectedNumbers[8] + $selectedNumbers[11] + $selectedNumbers[14] + $selectedNumbers[17]; $secondDigit = $secondSum % 10; $thirdSum = $selectedNumbers[3] + $selectedNumbers[6] + $selectedNumbers[9] + $selectedNumbers[12] + $selectedNumbers[15] + $selectedNumbers[18]; $thirdDigit = $thirdSum % 10; $result = $firstDigit + $secondDigit + $thirdDigit; if ($result === $target) { $bestMatch = $selectedNumbers; break; } } return $bestMatch; } }