| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 | <?phpnamespace App\Services;use App\Services\BaseService;use App\Models\Issue;use App\Models\Config;use Illuminate\Support\Facades\DB;use Illuminate\Support\Collection;use Illuminate\Support\Facades\Cache;use Illuminate\Support\Facades\Log;use App\Services\GameplayRuleService;use App\Constants\GameplayRuleEnum;use App\Http\Controllers\admin\Lottery;use App\Services\KeyboardService;use App\Services\LotteryImageService;use Telegram\Bot\FileUpload\InputFile;/** * 投注*/class IssueService extends BaseService {    /**     * @description: 模型     * @return {string}     */        public static function model() :string    {        return Issue::class;    }    /**     * @description: 枚举     * @return {*}     */        public static function enum() :string    {        return '';    }    /**     * @description: 获取查询条件     * @param {array} $search 查询内容     * @return {array}     */        public static function getWhere(array $search = []) :array    {        $where = [];        if(isset($search['issue_no']) && !empty($search['issue_no'])){            $where[] = ['issue_no', '=', $search['issue_no']];        }        if(isset($search['id']) && !empty($search['id'])){            $where[] = ['id', '=', $search['id']];        }        if(isset($search['status']) && !empty($search['status'])){            $where[] = ['status', '=', $search['status']];        }        return $where;    }     /**     * @description: 查询单条数据     * @param array $search     * @return \App\Models\Coin|null     */    public static function findOne(array $search): ?Issue    {        return self::model()::where(self::getWhere($search))->first();    }    /**     * @description: 查询所有数据     * @param array $search     * @return \Illuminate\Database\Eloquent\Collection     */    public static function findAll(array $search = [])    {        return self::model()::where(self::getWhere($search))->get();    }    /**     * @description: 分页查询     * @param array $search     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator     */    public static function paginate(array $search = [])    {        $limit = isset($search['limit'])?$search['limit']:15;        $paginator = self::model()::where(self::getWhere($search))->orderBy('issue_no','desc')->paginate($limit);        return ['total' => $paginator->total(), 'data' => $paginator->items()];    }    /**     * @description:      * @param {*} $params     * @return {*}     */        public static function submit($params = [])    {        $result = false;        $msg['code'] = self::NOT;        $msg['msg'] = '';                // 2. 判断是否是更新        if (!empty($params['id'])) {            // 更新            $info = self::findOne(['id'=>$params['id']] );            if (!$info) {                $msg['msg'] = '期号不存在!';            }else{                $result = $info->update($params);                $id = $params['id'];            }        } else {            // 创建            $result = $info = self::model()::create($params);            $id = $result->id;        }                       if($result){           $msg['code'] = self::YES;           $msg['msg'] = '设置成功';           $msg['key'] = $id;        }else{            $msg['msg'] = empty($msg['msg']) ?'操作失败':$msg['msg'];        }        return $msg;    }    /**     * @description: 开始下注     * @param {*} $id     * @return {*}     */    public static function betting($id)    {        $info = self::findOne(['id'=>$id]);        if(!$info){            return ['code'=>self::NOT, 'msg'=>'期号不存在'];        }        if(!in_array($info->status, [self::model()::STATUS_DRAFT,self::model()::STATUS_BETTING])){            return ['code'=>self::NOT, 'msg'=>'期号状态不正确'];        }        $info->status = self::model()::STATUS_BETTING;        $info->save();        // $text = "";        // $text .= "第".$info->issue_no."期\n";        // $text .= "🔥🔥🔥🔥🔥开始下注🔥🔥🔥🔥🔥\n";        $replyInfo = KeyboardService::findOne(['button' => '开始下注']);        if($replyInfo){            $text = $replyInfo->reply;            $buttons = json_decode($replyInfo->buttons,true);            $image = $replyInfo->image;            if($image){                $image = url($image);            }            self::bettingGroupNotice($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(empty($buttons)){                $buttons = self::getOperateButton();            }            self::bettingGroupNotice($text, $buttons, $image);        }        return ['code'=>self::YES, 'msg'=>'开始下注'];    }     /**     * @description: 封盘     * @param {*} $id     * @return {*}     */    public static function closeBetting($id)    {        $info = self::findOne(['id'=>$id]);        if(!$info){            return ['code'=>self::NOT, 'msg'=>'期号不存在'];        }        if($info->status != self::model()::STATUS_BETTING){            return ['code'=>self::NOT, 'msg'=>'期号状态不正确'];        }        $info->status = self::model()::STATUS_CLOSE;        $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);            }            self::bettingGroupNotice($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);            }            self::bettingGroupNotice($text, $buttons, $image);        }        return ['code'=>self::YES, 'msg'=>'封盘成功'];    }    /**     * @description: 开奖     * @param {*} $id     * @param {*} $winning_numbers 开奖号码     * @param {*} $combo 开奖组合     * @param {*} $recordImage 开奖图片     * @return {*}     */    public static function  lotteryDraw($id, $winning_numbers ,$combo ,$recordImage)    {        $info = self::findOne(['id'=>$id]);        if(!$info){            return ['code'=>self::NOT, 'msg'=>'期号不存在'];        }        if($info->status != self::model()::STATUS_CLOSE){            return ['code'=>self::NOT, 'msg'=>'期号状态不正确'];        }        // 计算中奖        $awards = self::award(explode(',',$winning_numbers));        DB::beginTransaction();        try {            $info->status = self::model()::STATUS_DRAW;            $info->winning_numbers = $winning_numbers;            $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(explode(',',$winning_numbers))." ".$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' => '✅ 唯一客服', 'callback_data' => "", 'url' => "https://t.me/{$serviceAccount}"]];                }                self::bettingGroupNotice($text, $buttons, $image ,true);            }            $recordImage = self::lotteryImage($info->issue_no);            if($recordImage){                self::bettingGroupNotice('', [], url($recordImage));            }            BetService::betSettled($info->issue_no, $awards);            DB::commit();            return ['code'=>self::YES, 'msg'=>'开奖成功'];        } catch (\Exception $e) {            DB::rollBack();            Log::error('开奖失败: '.$e->getMessage());            return ['code'=>self::NOT, 'msg'=>'开奖失败'];        }    }    /**     * @description: 获取中奖的奖项     * @param {*} $winning_numbers     * @return {*}     */        public static function award($winning_numbers)    {        $result = [];               // 组合        $sum = array_sum($winning_numbers);        $section = self::getSection($sum); // 总和段位        $result[] = $section;        $sumOddEven = self::calculateOddEven($sum); // 总和单双        $result[] = $sumOddEven;        $sumSize = self::calculateSumSize($sum);  // 总和大小        $result[] = $sumSize;        $sumExtremeSize = self::calculateSumExtremeSize($sum);  // 总和极值        if($sumExtremeSize){            $result[] = $sumExtremeSize;        }        $sumCao = $sum . '操';  // 总和数字        $result[] = $sumCao;        $sumCombo = $sumSize. $sumOddEven;  // 总和大小单双组合        $result[] = $sumCombo;        $sumBaoZi = self::isBaoZi($winning_numbers[0], $winning_numbers[1], $winning_numbers[2]); // 豹子        if($sumBaoZi){            $result[] = $sumBaoZi;        }        $sumPair = self::isPair($winning_numbers[0], $winning_numbers[1], $winning_numbers[2]); // 对子        if($sumPair){            $result[] = $sumPair;        }        $sumStraight = self::isStraight($winning_numbers[0], $winning_numbers[1], $winning_numbers[2]); // 顺子        if($sumStraight){            $result[] = $sumStraight;        }        $tail = self::getLastDigit($sum); // 总和尾数        $result[] = $tail . '尾'; // 尾数        $tailOddEven = self::calculateOddEven($tail); // 尾数单双        $result[] = '尾'.$tailOddEven;        $tailSize = self::calculateOneSize($tail); // 尾数大小        $result[] = '尾'.$tailSize;        $tailCombo = '尾'.$tailSize . $tailOddEven; // 尾数大小单双组合        $result[] = $tailCombo;        $numA = $winning_numbers[0];    // A球        $result[] = $numA.'A';        $numAOddEven = self::calculateOddEven($numA); // A球单双        $result[] = 'A'.$numAOddEven;        $numASize = self::calculateOneSize($numA); // A球大小        $result[] = 'A'.$numASize;        $result[] = 'A'.$numASize.$numAOddEven; // A球大小单双组合        $numB = $winning_numbers[1];    // B球        $result[] = $numB.'B';        $numBOddEven = self::calculateOddEven($numB); // B球        $result[] = 'B'.$numBOddEven;        $numBSize = self::calculateOneSize($numB); // B球大小        $result[] = 'B'.$numBSize;        $result[] = 'B'.$numBSize.$numBOddEven; // B球大小单双组合        $numC = $winning_numbers[2];        $result[] = $numC.'C';        $numCOddEven = self::calculateOddEven($numC); // C球单双        $result[] = 'C'.$numCOddEven;        $numCSize = self::calculateOneSize($numC); // C球大小        $result[] = 'C'.$numCSize;        $result[] = 'C'.$numCSize.$numCOddEven; // C球大小单双组合        return $result;    }    /**     * @description: 算单双     * @param {*} $number     * @return {*}     */        public static function calculateOddEven($number)    {        if ($number & 1) {            return GameplayRuleEnum::SINGLE;        } else {            return GameplayRuleEnum::DOUBLE;        }    }    /**     * @description: 总和大小     * @param {*} $number     * @return {*}     */        public static function calculateSumSize($number)    {        if($number >= GameplayRuleEnum::SUM_BIG) {            return GameplayRuleEnum::BIG;        }        if($number <= GameplayRuleEnum::SUM_SMALL){            return GameplayRuleEnum::SMALL;        }    }    /**     * @description: 总和极值     * @param {*} $number     * @return {*}     */        public static function calculateSumExtremeSize($number)    {        $result = '';        if($number >= GameplayRuleEnum::SUM_EXTREME_BIG) {            $result = GameplayRuleEnum::EXTREME_BIG;        }        if($number <= GameplayRuleEnum::SUM_EXTREME_SMALL){            $result = GameplayRuleEnum::EXTREME_SMALL;        }        return $result;    }    /**     * @description: 豹子     * @param {int} $a     * @param {int} $b     * @param {int} $c     * @return {*}     */        public static function isBaoZi(int $a, int $b, int $c)    {        $result = '';        if($a === $b && $b === $c){            $result = GameplayRuleEnum::BAO_ZI;        }        return $result;    }    /**     * @description: 对子     * @param {int} $a     * @param {int} $b     * @param {int} $c     * @return {*}     */    public static function isPair($a, $b, $c) {        $result = '';        // 确保输入都是个位数        if (!is_numeric($a) || !is_numeric($b) || !is_numeric($c) ||            $a < 0 || $a > 9 || $b < 0 || $b > 9 || $c < 0 || $c > 9) {            return ''; // 或者抛出异常        }                if(($a == $b && $a != $c) ||             ($a == $c && $a != $b) ||             ($b == $c && $b != $a)){            $result = GameplayRuleEnum::PAIRS;        }        // 判断是否为对子情况        return $result;    }    /**     * @description: 顺子     * @param {int} $a     * @param {int} $b     * @param {int} $c     * @return {*}     */    public static function isStraight($a, $b, $c) {        $result = '';        // 确保输入都是个位数(0-9)        if (!is_numeric($a) || !is_numeric($b) || !is_numeric($c) ||            $a < 0 || $a > 9 || $b < 0 || $b > 9 || $c < 0 || $c > 9) {            return '';        }            // 去重(顺子必须三个不同数字)        if ($a == $b || $a == $c || $b == $c) {            return '';        }            // 检查是否是完全升序或完全降序的连续数字        $numbers = [$a, $b, $c];        sort($numbers); // 排序后检查是否是 x, x+1, x+2        list($x, $y, $z) = $numbers;            // 情况1:升序连续(1,2,3)        $isAscending = ($x + 1 == $y) && ($y + 1 == $z);            // 情况2:降序连续(3,2,1)        $isDescending = ($z + 1 == $y) && ($y + 1 == $x);        if($isAscending || $isDescending){            $result = GameplayRuleEnum::STRAIGHT;        }        return $result;    }        /**     * 获取数字的尾数     * @param int $number 输入数字     * @return int 尾数     */    public static function getLastDigit($number) {        // 确保输入是整数        $number = (int)$number;        // 取绝对值,处理负数情况        $number = abs($number);        // 取模10得到尾数        return $number % 10;    }    /**     * @description: 尾大小     * @param {*} $number     * @return {*}     */        public static function calculateOneSize($number)    {        if($number >= GameplayRuleEnum::ONE_BIG) {            return GameplayRuleEnum::BIG;        }        if($number <= GameplayRuleEnum::ONE_SMALL){            return GameplayRuleEnum::SMALL;        }    }    /**     * @description: 获取段位     * @param {*} $number     * @return {*}     */    public static function getSection($number) {        $result = '';        if ($number >= GameplayRuleEnum::SECTION_1[0] && $number <= GameplayRuleEnum::SECTION_1[1]) {            $result = GameplayRuleEnum::ONE;        } elseif ($number >= GameplayRuleEnum::SECTION_2[0] && $number <= GameplayRuleEnum::SECTION_2[1]) {            $result = GameplayRuleEnum::TWO;        } elseif ($number >= GameplayRuleEnum::SECTION_3[0] && $number <= GameplayRuleEnum::SECTION_3[1]) {            $result = GameplayRuleEnum::THREE;        } elseif ($number >= GameplayRuleEnum::SECTION_4[0] && $number <= GameplayRuleEnum::SECTION_4[1]) {            $result = GameplayRuleEnum::FOUR;        }        return $result; // 不在任何段中    }    /**     * @description: 近期开奖记录     * @return {*}     */        public static function currentLotteryResults($memberId)    {        // $result = self::model()::where('status', self::model()::STATUS_DRAW)->orderBy('id','desc')->take(16)->get();        // $text = "📅 近期开奖记录\n";        // $text .= "====================\n";        // if($result){        //     foreach($result as $k => $v){        //         $winArr = explode(',',$v->winning_numbers);        //         // 组合        //         $sum = array_sum($winArr);        //         $combo = [];        //         $sumOddEven = self::calculateOddEven($sum); // 总和单双        //         $sumSize = self::calculateSumSize($sum);  // 总和大小        //         $sumExtremeSize = self::calculateSumExtremeSize($sum);  // 总和极值        //         if(empty($sumExtremeSize)){        //             $sumExtremeSize = "-";        //         }                     //         $tail = self::getLastDigit($sum); // 总和尾数        //         if($tail == 0){        //             $tail = '-'; // 尾数        //         }else{        //             $tail = '尾'.$tail; // 尾数        //         }                        //         $text .= "回合:{$v->issue_no}期 \n";        //         $text .= "结果:".implode('+',explode(',',$v->winning_numbers))."=".array_sum(explode(',',$v->winning_numbers))." \n";        //         $text .= "组合:{$sumSize} {$sumOddEven} \n";        //         $text .= "极值:{$sumExtremeSize} \n";        //         $text .= "尾数:{$tail} \n";        //         $text .= "---------------------------\n";        //     }        //     self::telegram()->sendMessage([        //             'chat_id' => $memberId,        //             'text' => $text,        //         ]);        // }else{        //     self::telegram()->sendMessage([        //             'chat_id' => $memberId,        //             'text' => "暂无开奖记录",        //         ]);        // }        $result = self::model()::where('status', self::model()::STATUS_DRAW)->orderBy('id','desc')->first();        if($result){            if($result->image){                self::telegram()->sendPhoto([                    'chat_id' => $memberId,                    'photo' => InputFile::create(url($result->image)),                ]);            }else{                // if($result->combo){                //     self::telegram()->sendMessage([                //         'chat_id' => $memberId,                //         'text' => "",                //     ]);                // }else{                    self::telegram()->sendMessage([                        'chat_id' => $memberId,                        'text' => "暂无开奖记录",                    ]);                // }                            }                    }    }    // 获取最新的开奖数据    public static function getLatestIssue()    {        $url = "https://ydpc28.co/api/pc28/list";        $result = file_get_contents($url);        $result = json_decode($result,true);        if($result['errorCode'] != 0){            return ['code'=>self::NOT, 'msg'=>'获取最新期号失败'];        }        $nextDrawInfo = $result['data']['nextDrawInfo'];        if($nextDrawInfo['nextDrawTime'] >= date('H:i:s')) {            $endTime = date('Y-m-d').' '.$nextDrawInfo['nextDrawTime']; // 下一期的截止时间        }else{            $endTime = date('Y-m-d',strtotime('+1 day')).' '.$nextDrawInfo['nextDrawTime']; // 下一期的截止时间        }                $list = $result['data']['list'];        $listKey = [];        foreach($list as $k => $v){            $listKey[$v['lotNumber']] = $v;        }        $oldList = self::findAll(['status' => self::model()::STATUS_CLOSE]);    // 获取所有封盘的期号        foreach($oldList as $k => $v){            if(isset($listKey[$v->issue_no])){                $issue = $listKey[$v->issue_no];                $winning_numbers = implode(',', str_split((string)$issue['openCode']));                $winArr = explode(',',$winning_numbers);                // 组合                $sum = array_sum($winArr);                $combo = [];                $sumOddEven = self::calculateOddEven($sum); // 总和单双                $combo[] = $sumOddEven;                $sumSize = self::calculateSumSize($sum);  // 总和大小                $combo[] = $sumSize;                $sumExtremeSize = self::calculateSumExtremeSize($sum);  // 总和极值                if($sumExtremeSize){                    $combo[] = $sumExtremeSize;                }                        $sumBaoZi = self::isBaoZi($winArr[0], $winArr[1], $winArr[2]); // 豹子                if($sumBaoZi){                    $combo[] = $sumBaoZi;                }                $sumPair = self::isPair($winArr[0], $winArr[1], $winArr[2]); // 对子                if($sumPair){                    $combo[] = $sumPair;                }                $sumStraight = self::isStraight($winArr[0], $winArr[1], $winArr[2]); // 顺子                if($sumStraight){                    $combo[] = $sumStraight;                }                $tail = self::getLastDigit($sum); // 总和尾数                if($tail == 0){                                    }else{                     $combo[] = '尾'.$tail; // 尾数                }                               $combo = implode(' ', $combo);                self::lotteryDraw($v->id, $winning_numbers, $combo,'');            }        }        sleep(3); // 等待开奖完成        $latestIssue = $list[0];    // 最后开奖                $new_issue_no = $latestIssue['lotNumber'] + 1;  // 新期号        $newInfo = self::findOne(['issue_no' => $new_issue_no]);   // 找新的期号                // 不存在        if(!$newInfo){            $res = self::submit([                'issue_no' => $new_issue_no,                'status' => self::model()::STATUS_DRAFT,                'start_time' => date('Y-m-d H:i:s'),                'end_time' => $endTime,            ]);            $id = $res['key']??0;            if($id){                self::betting($id); // 开始下注            }        }                return $result;    }    // 封盘倒数    public static function syncCountdownIssue()    {        $now_date = date('Y-m-d H:i:s',time() + 50); // 提前50秒        $info = self::model()::where('status', self::model()::STATUS_BETTING)->orderBy('end_time','asc')->first();        if($info){            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)){                                            }else{                        self::bettingGroupNotice($text, $buttons, $image);                        Cache::put('issue_countdown_'.$info->id, true, 60); // 缓存50秒,防止多次发送                    }                                    }            }        }                    }    // 停止下注    public static function syncCloseIssue()    {        $now_date = date('Y-m-d H:i:s',time() + 30); // 提前30秒        $list = self::findAll(['status' => self::model()::STATUS_BETTING]);        foreach($list as $k => $v){            if($v['end_time'] < $now_date){                self::closeBetting($v->id);            }        }    }    // 生成开奖图片    public static function lotteryImage($issue_no)    {        $list = self::model()::where('issue_no','<=',$issue_no)->where(self::getWhere(['status' => self::model()::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 = self::calculateOddEven($sum); // 总和单双            $sumSize = self::calculateSumSize($sum);  // 总和大小            $v['combo'] = $sumSize . ' ' . $sumOddEven;            $sumExtremeSize = self::calculateSumExtremeSize($sum);  // 总和极值            if(!$sumExtremeSize){                $sumExtremeSize = '-';            }            $v['extreme'] = $sumExtremeSize;            $tail = self::getLastDigit($sum); // 总和尾数            if($tail === 0){                $tailStr = '-';            }else{                $tailStr = '尾' . $tail;            }            $v['tail'] = $tailStr;            $records[$k] = $v;        }        $service = new LotteryImageService();        $url = $service->generate($records);        self::model()::where('issue_no', $issue_no)->update(['image' => $url]);        return $url;    }}
 |