playTypeService = app(PlayTypeService::class); } public function playTypeNames() { return [ PlayType::LQ_DXF => '大小分', PlayType::LQ_SFC => '胜分差', PlayType::LQ_RF => '让分胜负', PlayType::LQ_SF => '胜负', ]; } public function getPlayTypeName($playType) { $fieldNames = $this->playTypeNames(); $result = $fieldNames[$playType]; return $result; } public function resultFieldNames() { return [ 'handicap' => '让球数', // sf_odds胜负, rf_odds让分胜负 'single' => '单关', 'win' => '主胜', //如果是rf_odds,为让分主胜 'loss' => '客胜',//如果是rf_odds,为让分客胜 'w1' => '主胜1-5', 'w2' => '主胜6-10', 'w3' => '主胜11-15', 'w4' => '主胜16-20', 'w5' => '主胜21-25', 'w6' => '主胜26+', 'l1' => '客胜1-5', 'l2' => '客胜6-10', 'l3' => '客胜11-15', 'l4' => '客胜16-20', 'l5' => '客胜21-25', 'l6' => '客胜26+', 'big' => '大分', 'small' => '小分' ]; } public static function inWinFields($playType, $field) { $fields = self::winFields($playType); return in_array($field, $fields); } public static function winFields($playType) { if ($playType == PlayType::LQ_SF || $playType == PlayType::LQ_RF) { return ['win']; } if ($playType == PlayType::LQ_SFC) { return [ 'w1', 'w2', 'w3', 'w4', 'w5', 'w6', ]; } if ($playType == PlayType::LQ_DXF) { return ['big', 'small']; } return []; } public static function inLossFields($playType, $field) { $fields = self::lossFields($playType); return in_array($field, $fields); } public static function lossFields($playType) { if ($playType == PlayType::LQ_SF || $playType == PlayType::LQ_RF) { return ['loss']; } if ($playType == PlayType::LQ_SFC) { return [ 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', ]; } if ($playType == PlayType::LQ_DXF) { return ['big', 'small']; } return []; } public function maxPrizeSpliceWdlOdds($matchOdds, $rqHandicap = null) { $winArray = []; $lossArray = []; foreach ($matchOdds as $playType => $playData) { foreach ($playData as $field => $odds) { if ($playType == PlayType::LQ_RF) { $rqNum = $rqHandicap; if ($rqNum > 0) { if ($field == 'win') { $winArray[PlayType::LQ_RF][$field] = $odds; $lossArray[PlayType::LQ_RF][$field] = $odds; } if ($field == 'loss') { $lossArray[PlayType::LQ_RF][$field] = $odds; } } else if ($rqNum < 0) { if ($field == 'win') { $winArray[PlayType::LQ_RF][$field] = $odds; } if ($field == 'loss') { $winArray[PlayType::LQ_RF][$field] = $odds; $lossArray[PlayType::LQ_RF][$field] = $odds; } } } else { if (JclqService::inWinFields($playType, $field)) { $winArray[$playType][$field] = $odds; } if (JclqService::inLossFields($playType, $field)) { $lossArray[$playType][$field] = $odds; } } } } foreach ($winArray as $playType => $playData) { $winArray[$playType] = $this->maxPrizeSearchMaxOdd($playData); } foreach ($lossArray as $playType => $playData) { $lossArray[$playType] = $this->maxPrizeSearchMaxOdd($playData); } $winOdds = $this->maxPrizeSumPlayOdd($winArray); $maxOdds = $winOdds; $result = $winArray; $lossOdds = $this->maxPrizeSumPlayOdd($lossArray); if ($lossOdds > $maxOdds) { $result = $lossArray; } return $result; } /** * @param $oddsData {id => {rf_odds:{win:1.1}}} * @param $handicapList {id => 11} * @return array */ public function maxPrizeZuheList($oddsData, $passModes, $handicapList) { foreach ($oddsData as $id => $matchOddsData) { $handicap = $handicapList[$id]; $searchResult = $this->maxPrizeSpliceWdlOdds($matchOddsData, $handicap); $result[$id] = $searchResult; } $zuhes = $this->generateBetsInfo($result,$passModes, 1); return $zuhes; } /** * @param $oddsData {id => {rf_odds:{win:1.1}}} * @param $handicapList {id => 11} * @return array */ public function maxPrizeCompute($oddsData,$passModes, $handicapList) { $zuhes = $this->maxPrizeZuheList($oddsData,$passModes, $handicapList); $prize = 0; foreach ($zuhes as $zuhe) { $prize += $zuhe['all_odds'] * 2; } return $prize; } public function getResultFieldName($playType, $field) { $fieldNames = $this->resultFieldNames(); $result = $fieldNames[$field]; if ($playType == 'rf_odds') { return '让分' . $result; } if (!in_array($field, ['win', 'loss', 'draw']) || $playType != 'rq_odds') { return $result; } return '让' . $result; } public static function generateLqPassModeInfo($oddData, $playType) { $changNum = count($oddData); if ($changNum == 1) { $oddsId = array_key_first($oddData); $jclqOdds = JclqOdds::find($oddsId); $oddInfo = $oddData[$oddsId]; foreach ($oddInfo as $play =>$v) { $info = $jclqOdds->{$play}; ThrowException::isTrue(!$info, '无此玩法:'.$play); ThrowException::isTrue($info['single'] != 1, '该玩法不支持单关'.$play); } return [ 'multi' => [['key' => '1.1', 'title' => '单关']], 'single' => [] ]; } $hasSfc = false; foreach ($oddData as $id => $oddInfo) { foreach ($oddInfo as $play => $v) { if ($play == PlayType::LQ_SFC) { $hasSfc = true; break; } } if ($hasSfc) { break; } } $maxChuan = $changNum; if ($hasSfc && ($playType == PlayType::MIXED || $playType == PlayType::LQ_SFC)) { if ($changNum > 4) { // 胜分差最多4串1 $maxChuan = 4; } } $rules = self::passModes(); /** @var JclqService $service */ $service = app(JclqService::class); $hasSingle = $service->getSingleOdds($oddData); $one = []; $multi = []; foreach ($rules as $chang => $zhuData) { if ($chang == 1) { if ($hasSingle) { $multi[] = [ 'key' => sprintf('%d.%d', $chang, 1), 'title' => '单关', ]; } continue; } if ($chang > $maxChuan) { continue; } foreach ($zhuData as $k => $zhu) { $item = [ 'key' => sprintf('%d.%d', $chang, $k), 'title' => sprintf('%d串%d', $chang, $k), ]; if ($chang <= $maxChuan && $k == 1) { $multi[] = $item; } if ($chang == $maxChuan && $k >= $maxChuan && !isset($zhu[1])) { $one[] = $item; } } } sort($one); return [ 'multi' => $multi, 'single' => $one ]; } public function getSingleOdds($oddData) { $oddsIds = array_keys($oddData); if (!$oddsIds) { return []; } $jclqOdds = JclqOdds::whereIn('id', $oddsIds)->get(); $result = []; foreach ($jclqOdds as $odd) { $oddDataItem = Arr::get($oddData, $odd->id); ThrowException::isTrue(!$oddDataItem, '单关比赛不存在'); foreach ($oddDataItem as $playType => $playData) { foreach ($playData as $key => $val) { if ($odd->{$playType} === null) { Log::error('jclqService:getSingleOdds not found playType', [ 'oddsData' => $oddData, 'oddDataItem' => $oddDataItem, 'playType' => $playType, 'odd' => $odd->toArray(), ]); ThrowException::run('单关数据有误'); } if (Arr::get($odd->{$playType}, 'single') != 1) { return []; } $result[] = [ $this->generateJclqCombinationItem($odd->id, $playType, $key) ]; } } } return $result; } /** * @param Customer $customer * @return mixed */ public function saleLotteries(Customer $customer, $lotteryTypeId){ $lotteryType = LotteryType::where('type', LottType::JCLQ) ->where('status', BoolEnum::YES) ->find($lotteryTypeId); ThrowException::isTrue(!$lotteryType, '不支持此彩种'); $lottery = Lottery::active() ->shopAndType($customer->shop_id, $lotteryTypeId) ->first(); ThrowException::isTrue(!$lotteryType, '店铺不支持此彩种'); $odds = JclqOdds::selling() ->where('close_time', '>', date('Y-m-d H:i:s', time() + $lottery->earlySecond())) ->orderBy('issue_num', 'asc') ->get(); $result = [ 'play_types' => PlayType::asJclqSelectArray(), ]; $competitions = []; /** @var JclqOdds $odd */ foreach ($odds as $odd) { if (!in_array($odd->jc_competition_name, $competitions)) { $competitions[] = $odd->jc_competition_name; } $odd->jc_competition_name = preg_replace('/[0-9]/', '', $odd->jc_competition_name); $closeTime = $odd->getCloseTime($lottery->earlySecond()); $odd->real_close_time = $closeTime; $odd->real_close_str = date('H:i', strtotime($closeTime)) . '截止'; $odd->sf_odds = Helps::compareOdds($odd->sf_odds, $odd->sf_odds_last); $odd->rf_odds = Helps::compareOdds($odd->rf_odds, $odd->rf_odds_last); $odd->sfc_odds = Helps::compareOdds($odd->sfc_odds, $odd->sfc_odds_last); $odd->dxf_odds = Helps::compareOdds($odd->dxf_odds, $odd->dxf_odds_last); JclqOdds::unsetLastSuffixField($odd); } if ($competitions) { array_unshift($competitions, '全部'); } $result['competitions'] = $competitions; $result['odds'] = $odds; return $result; } public function valid(Lottery $lottery, $playType, $data) { ThrowException::isTrue(count($data) > 8, '最多只能选择八场比赛'); $this->playTypeService->validLqPlayType($playType, $data); if ($lottery->plan_multi == BoolEnum::YES) { $allowPlanNum = $lottery->plan_num; $this->validZuHe($allowPlanNum, $data); } $odds = []; $oneMutilNum = 0; foreach ($data as $id => $item) { $odds = array_merge($odds, array_keys($item)); if (count($item) > 1) { $oneMutilNum += 1; } } if ($lottery->one_multi == BoolEnum::YES && $oneMutilNum > 1) { JingCaiException::throwJingcai("只能选择其中一场比赛进行玩法多选"); } $oddsCount = JclqOdds::whereIn('id', array_keys($data))->count(); ThrowException::isTrue($oddsCount != count($data), '比赛信息有误'); } /** * 校验组合方案 */ public function validZuHe($allowPlanNum, $data, $combinationLen=2) { $oddsMatch = $this->generateCombinationInput($data); $zuhes = Helps::getCombinationData($oddsMatch, $combinationLen); if (count($zuhes) > $allowPlanNum) { JingCaiException::throwJingcai("允许的方案组合不超过{$allowPlanNum}个"); } } /** * 计算价格 * @param $data 数据 * @param $betsNum 注数 * @return mixed */ public function computePrizeInfo($data, $betsNum = 1, $mnKeys = []) { return $this->computePrizeInfoV3($data, $betsNum, $mnKeys); sort($mnKeys); $zhuTotal = 0; $min = 0; $max = 0; foreach ($mnKeys as $key) { $passModes = self::getPassMode($key); foreach ($passModes as $chang => $changeGe) { $prizeInfo = $this->generatePrizeOdds($data, $chang); $zhuTotal += $prizeInfo['zhu_num']; if (!$min) { $min = $prizeInfo['min']; } if ($prizeInfo['min'] < $min) { $min = $prizeInfo['min']; } $max += $prizeInfo['max']; } } return [ 'zhu_num' => $zhuTotal, 'expect_bets' => $max, 'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()), 'prize_min' => Helps::floatFormat($min * $betsNum * Config::lotteryUnitPrice()), 'prize_max' => Helps::floatFormat($max * $betsNum * Config::lotteryUnitPrice()) ]; } public function computePrizeInfoV3($data, $betsNum = 1, $passModeKeys = []) { $piaos = $this->createPiaoV3($data, $passModeKeys, $betsNum); $maxPrize = 0; $minPrize = null; $maxPrizeIndex = null; $allBetsResultUnique = []; $zhuTotal = 0; foreach ($piaos as $idx => $piao) { if ($piao['prize'] > $maxPrize) { $maxPrize = $piao['prize']; $maxPrizeIndex = $idx; } foreach ($piao['bets'] as $betsInfo) { $zhuTotal += 1; @$allBetsResultUnique[$betsInfo['unique']] += 1; $betItemPrize = $this->getBetsInfoPrize($betsInfo); if (isset($minPrize)) { $minPrize = $minPrize < $betItemPrize ? $minPrize : $betItemPrize; } else { $minPrize = $betItemPrize; } } } $jclqOdds = JclqOdds::whereIn('id', array_keys($data))->pluck('rf_odds', 'id')->toArray(); $handicapList = []; foreach ($jclqOdds as $id => $item) { if ($item) { $handicapList[$id] = $item['handicap']; } } $maxZuheList = $this->maxPrizeZuheList($data, $passModeKeys, $handicapList); $maxPrize = 0; foreach ($maxZuheList as $zuhe) { $repeatNum = $allBetsResultUnique[$zuhe['unique']]; $maxPrize += $repeatNum * $this->getBetsInfoPrize($zuhe); } $maxPrize *= $betsNum; return [ 'zhu_num' => $zhuTotal, 'expect_bets' => Helps::floatFormat( $maxPrize / $betsNum / Config::lotteryUnitPrice()), 'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()), 'prize_min' => Helps::floatFormat($minPrize), 'prize_max' => Helps::floatFormat($maxPrize), ]; } public function computePrizeInfoV2($data, $betsNum = 1, $passModeKeys = []) { sort($passModeKeys); $lastKey = array_pop($passModeKeys); // 最大的串法 $betsList = $this->generateBetsInfo($data, [$lastKey], $betsNum); $maxBetsOdd = 0; $maxUnique = ''; foreach ($betsList as $item) { if ($item['all_odds'] > $maxBetsOdd) { $maxBetsOdd = $item['all_odds']; $maxUnique = $item['unique']; } } $allBetsResultUnique = []; $allBetsResult = $betsList; $allPrizes = []; $maxUniqueArray = []; // 其余串法 foreach ($betsList as $item) { $betItemPrize = $this->getBetsInfoPrize($item); if ($item['unique'] == $maxUnique) { $maxUniqueArray[] = $item['unique']; } @$allBetsResultUnique[$item['unique']] += 1; $keyOddsData = $this->betsInfoToOdds($item); foreach ($passModeKeys as $key) { $keyBetsData = $this->generateBetsInfo($keyOddsData, [$key], $betsNum); foreach ($keyBetsData as $kitem) { @$allBetsResultUnique[$kitem['unique']] += 1; $betKItemPrize = $this->getBetsInfoPrize($kitem); @$allPrizes[$kitem['unique']] += $betKItemPrize; if ($item['unique'] == $maxUnique) { $maxUniqueArray[] = $kitem['unique']; } } $allBetsResult = array_merge($allBetsResult, $keyBetsData); } $allPrizes[$item['unique']] = $betItemPrize; } $maxPrize = 0; foreach ($allPrizes as $unique => $prize) { if (in_array($unique, $maxUniqueArray)) { $maxPrize += $prize; } } sort($allPrizes); $minPrize = $allPrizes[0]; $zhuTotal = count($allBetsResult); return [ 'zhu_num' => $zhuTotal, 'expect_bets' => $maxPrize / $betsNum / Config::lotteryUnitPrice(), 'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()), 'prize_min' => Helps::floatFormat($minPrize), 'prize_max' => Helps::floatFormat($maxPrize), ]; } public function generateJclqCombinationItem($id, $playType, $result) { return sprintf('%d-%s-%s', $id, $playType, $result); } public function parseJclqCombinationItem($key) { $info = explode('-', $key); return [ 'id' => $info[0], 'play' => $info[1], 'result' => $info[2], ]; } public function generatePrizeOdds($data, $len) { // 说明是单关 if ($len == 1) { $combinationData = $this->getSingleOdds($data); } else { $fdata = $this->generateCombinationInput($data); if (!$fdata) { Log::error('generatePrize格式化数据失败', [ 'data' => $data, 'len' => $len ]); ThrowException::run('数据有误,无法计算'); } $combinationData = Helps::getCombinationData($fdata, $len); if (!$combinationData) { Log::error('generatePrize生成组合数据失败', [ 'fdata' => $fdata, 'len' => $len ]); ThrowException::run('数据有误,无法组合'); } } $oddsAll = []; $zhuTotal = count($combinationData); foreach ($combinationData as $keyArr) { $keyOdds = 1; // 基础赔率 foreach ($keyArr as $key) { $keyInfo = $this->parseJclqCombinationItem($key); $baseItemArr = Arr::get($data, $keyInfo['id']); $odds = Arr::get($baseItemArr, $keyInfo['play'] . '.' . $keyInfo['result'], null); $keyOdds *= $odds; } $oddsAll[] = $keyOdds; } sort($oddsAll, SORT_ASC); return [ 'zhu_num' => $zhuTotal, 'min' => $oddsAll[0], 'max' => $oddsAll[count($oddsAll) - 1], 'odds_all' => $oddsAll, ]; } public function generateCombinationInput($data, $hasOdds = false) { $result = []; foreach ($data as $id => $item) { $resItem = []; foreach ($item as $k => $itemData) { foreach ($itemData as $kk => $kkv) { $resKey = $this->generateJclqCombinationItem($id, $k, $kk); if ($hasOdds) { $resItem[$resKey] = $kkv; } else { $resItem[$resKey] = $resKey; } } } $result[] = $resItem; } return $result; } public function getJczqOddsFromData(Lottery $lottery, $oddsData) { $odds = JclqOdds::selling() ->whereIn('id', array_keys($oddsData)) ->orderBy('close_time', 'asc') ->orderBy('play_num', 'asc') ->get(); ThrowException::isTrue(count($odds) != count($oddsData), '比赛信息有误'); $result = []; /** @var JclqOdds $odd */ foreach ($odds as $odd) { $odd->jc_competition_name = preg_replace('/[0-9]/', '', $odd->jc_competition_name); $closeTime = $odd->getCloseTime($lottery->earlySecond()); $odd->real_close_time = $closeTime; $odd->real_close_str = date('H:i', strtotime($closeTime)) . '截止'; unset($odd->sf_odds_last); unset($odd->rf_odds_last); unset($odd->sfc_odds_last); unset($odd->dxf_odds_last); if (@$oddsData[$odd->id]['sf_odds']) { $odd->sf_odds = Helps::copyProperty($odd->sf_odds, $oddsData[$odd->id]['sf_odds']); } else { unset($odd->sf_odds); } if (@$oddsData[$odd->id]['rf_odds']) { $odd->rf_odds = Helps::copyProperty($odd->rf_odds, $oddsData[$odd->id]['rf_odds']); } else { unset($odd->rf_odds); } if (@$oddsData[$odd->id]['sfc_odds']) { $odd->sfc_odds = Helps::copyProperty($odd->sfc_odds, $oddsData[$odd->id]['sfc_odds']); } else { unset($odd->sfc_odds); } if (@$oddsData[$odd->id]['dxf_odds']) { $odd->dxf_odds = Helps::copyProperty($odd->dxf_odds, $oddsData[$odd->id]['dxf_odds']); } else { unset($odd->dxf_odds); } $result[] = $odd; } return $result; } /** * 刷新数据的赔率 * @param $data * @return mixed */ public function refreshOdds($data){ $ids = array_keys($data); ThrowException::isTrue(!$ids, '请选择比赛进行投注'); $odds = JclqOdds::whereIn('id', $ids)->get(); $odds = collect($odds); ThrowException::isTrue($odds->count() != count($ids), '比赛数据错误,请重新选择'); $result = []; $oddsExtra = []; foreach ($data as $id => $val) { $item = []; $itemExtra = []; foreach ($val as $playType => $playData) { $oddItem = $odds->where('id', $id)->first(); foreach ($playData as $k => $v) { $odd = Arr::get($oddItem, $playType . '.' . $k); if (!$odd) { Log::error('JclqService->refreshOdds数据错误', [ 'data' => $data, 'key' => $playType . '.' . $k, 'val' => $odd, 'id' => $id, ]); } ThrowException::isTrue($odd === null,'数据错误,请重新选择'); $item[$playType][$k] = Arr::get($oddItem, $playType . '.' . $k); $itemExtra[$playType] = Arr::get($oddItem, $playType); } } $result[$id] = $item; $oddsExtra[$id] = $itemExtra; } return [ 'odds' => $result, 'odds_raw' => $oddsExtra ]; } public function piaoMatchCanAddPlay($piao, $betsInfo) { foreach ($piao['bets'] as $item) { $intersectIds = array_intersect($item['ids'], $betsInfo['ids']); if ($intersectIds) { foreach ($intersectIds as $id) { if ($item['info'][$id]['play'] != $betsInfo['info'][$id]['play']) { return false; } } } } return true; } public function piaoAddBets(&$piaos, $betsInfo) { $addPiao = false; if (!$piaos) { $piaos = []; $betsNumAll = $betsInfo['bets_num']; // 超出限制,添加一部分,返回剩余的 if ($betsNumAll > Config::piaoMaxBetsNum()) { $addNum = Config::piaoMaxBetsNum(); $tempBetsInfo = $betsInfo; $betsInfo['bets_num'] = $addNum; $piaos[0]['bets'][] = $betsInfo; $piaos[0]['bets_num'] = $addNum; $tempBetsInfo['bets_num'] -= $addNum; return $this->piaoAddBets($piaos, $tempBetsInfo); } $piaos[0] = [ 'bets' => [$betsInfo], 'bets_num' => $betsInfo['bets_num'] ]; $addPiao = true; return $addPiao; } foreach ($piaos as $pk => $piao) { if ($piaos[$pk]['bets_num'] >= Config::piaoMaxBetsNum()) { continue; } // 同一场只能出现一个玩法 $can = $this->piaoMatchCanAddPlay($piao, $betsInfo); if (!$can) { continue; } $betsNumAll = $piaos[$pk]['bets_num'] + $betsInfo['bets_num']; // 超出限制,添加一部分,返回剩余的 if ($betsNumAll > Config::piaoMaxBetsNum()) { $addNum = Config::piaoMaxBetsNum() - $piaos[$pk]['bets_num']; $tempBetsInfo = $betsInfo; $betsInfo['bets_num'] = $addNum; $piaos[$pk]['bets'][] = $betsInfo; $piaos[$pk]['bets_num'] += $addNum; $tempBetsInfo['bets_num'] -= $addNum; return $this->piaoAddBets($piaos, $tempBetsInfo); } $addPiao = true; $piaos[$pk]['bets'][] = $betsInfo; $piaos[$pk]['bets_num'] += $betsInfo['bets_num']; } if (!$addPiao) { $nextPk = count($piaos); $betsNumAll = $betsInfo['bets_num']; // 超出限制,添加一部分,返回剩余的 if ($betsNumAll > Config::piaoMaxBetsNum()) { $addNum = Config::piaoMaxBetsNum(); $tempBetsInfo = $betsInfo; $betsInfo['bets_num'] = $addNum; $piaos[$nextPk]['bets'][] = $betsInfo; $piaos[$nextPk]['bets_num'] = $addNum; $tempBetsInfo['bets_num'] -= $addNum; return $this->piaoAddBets($piaos, $tempBetsInfo); } $piaos[$nextPk] = [ 'bets' => [$betsInfo], 'bets_num' => $betsInfo['bets_num'] ]; } } public function createPiaos($betsInfos) { $piaos = []; foreach ($betsInfos as $betsInfo) { $this->piaoAddBets($piaos, $betsInfo); } return $piaos; } public function getBetsInfoFromCombinationData($data, $betsNum = 1, $dataOdd) { $result = []; foreach ($data as $zuheInfo) { $resultItem = []; $allOdds = 1; foreach ($zuheInfo as $key) { $keyInfo = $this->parseJclqCombinationItem($key); $keyInfo['odd'] = $this->getBetsOddFromCombinationData($key, $dataOdd); $allOdds *= $keyInfo['odd']; $resultItem['ids'][] = intval($keyInfo['id']); $resultItem['keys'][] = $key; $resultItem['info'][$keyInfo['id']] = $keyInfo; $resultItem['bets_num'] = $betsNum; } $tempKeys = $resultItem['keys']; sort($tempKeys); $resultItem['unique'] = implode(';', $tempKeys); $resultItem['all_odds'] = $allOdds; $resultItem['chuan_num'] = count($resultItem['ids']); $result[] = $resultItem; } return $result; } public function generateBetsInfo($odds, $passModeKeys, $betsNum) { $data = $this->generateCombinationInput($odds); $result = []; foreach ($passModeKeys as $key) { $passModes = self::getPassMode($key); foreach ($passModes as $chang => $changeGe) { if ($chang == 1) { $combinationData = $this->getSingleOdds($odds); } else { $combinationData = Helps::getCombinationData($data, $chang); } $result = array_merge($result, $combinationData); } } $dataOdd = $this->generateCombinationInput($odds, true); return $this->getBetsInfoFromCombinationData($result, $betsNum, $dataOdd); } /** * @param Customer $customer * @param $data * @return Order */ public function createOrder(Customer $customer, $data) { $lotteryTypeId = Arr::get($data, 'lottery_type_id'); $playType = Arr::get($data, 'play_type'); $type = Arr::get($data, 'type', OrderType::NORMAL); $fadanSecret = Arr::get($data, 'type_mode', 1); $fadanDesc = Arr::get($data, 'type_desc', ''); $betsNum = Arr::get($data, 'bets_num'); $passModeKeys = Arr::get($data, 'pass_mode_keys'); $odds = Arr::get($data, 'odds'); // 购买的场次或投注信息 $union_piece_total = intval(Arr::get($data, 'union_piece_total', 0)); $union_piece_buy = intval(Arr::get($data, 'union_piece_buy', 0)); $union_piece_keep = intval(Arr::get($data, 'union_piece_keep', 0)); $union_keep = Arr::get($data, 'union_keep', BoolEnum::NO); $union_brokerage = intval(Arr::get($data, 'union_brokerage', 0)); $fadan_order_no = Arr::get($data, 'fadan_order_no', ''); ThrowException::isTrue(!$passModeKeys, '请选择m串n'); if ($type == OrderType::FADAN) { ThrowException::isTrue(!$fadanDesc,'请填写发单宣言!'); $this->canCreateFanDanOrder($customer->id); } ThrowException::isTrue(!PlayType::hasValue($playType),'无效的玩法!'); /** @var Lottery $lott */ $lott = LotteryService::getLottery($customer->shop->id, $lotteryTypeId); throw_if(!$lott, JingCaiException::create('该彩种暂不支持下单!')); $this->valid($lott, $playType, $odds); $oddsInfo = $this->refreshOdds($odds); $odds = $oddsInfo['odds']; $computeInfo = $this->computePrizeInfo($odds, $betsNum, $passModeKeys); $lott->validMixMoney($computeInfo['money']); if ($type == OrderType::FADAN) { throw_if(!$fadanDesc, JingCaiException::create('请填写发单宣言!')); $this->canCreateFanDanOrder($customer->id); ThrowException::isTrue($this->fadanValid($computeInfo['money'], $computeInfo['prize_min']), '最低奖金大于等于投注金额的1.6倍'); } if ($type == OrderType::UNION) { $lott->validEnableHemai(); throw_if(!$fadanDesc, JingCaiException::create('请填写合买宣言!')); ThrowException::isTrue($union_piece_total <= 0, '总份数不能小于0'); $piecePrice = $computeInfo['money'] / $union_piece_total; ThrowException::isTrue($piecePrice <= 1, '每份金额必须大于1'); ThrowException::isTrue($union_piece_buy > $union_piece_total, '超过方案总金额'); if ($union_keep == BoolEnum::YES) { $union_piece_keep = $union_piece_total - $union_piece_buy; } $this->canCreateUnionOrder($customer->id); } $pid = 0; if ($type == OrderType::GENDAN) { $fadanOrder = Order::sn($fadan_order_no)->first(); ThrowException::isTrue(!$fadanOrder, '所跟订单不存在'); ThrowException::isTrue($fadanOrder->lottery_state != LottState::WAIT, '订单状态有误'); ThrowException::isTrue(date('Y-m-d H:i:s') > $fadanOrder->odds_early_close_time, '所跟订单已结束投注'); $pid = $fadanOrder->id; $fadanSecret = $fadanOrder->type_mode; } DB::beginTransaction(); try { $jclqOdds = JclqOdds::whereIn('id', array_keys($odds))->get(); $closeTimes = []; $oddsCloseTimes = []; /** @var JclqOdds $odd */ foreach ($jclqOdds as $odd) { $real_close_time = $odd->getCloseTime($lott->earlySecond()); $closeTimes[] = $real_close_time; $oddsCloseTimes[] = $odd->getCloseTime(0); } sort($closeTimes); sort($oddsCloseTimes); $earlyTime = $closeTimes[0]; $oddsCloseTime = $oddsCloseTimes[0]; $lateTime = $closeTimes[count($closeTimes) - 1]; $this->checkCloseTimeOver($earlyTime); // $betsInfos = $this->generateBetsInfo($odds, $passModeKeys, $betsNum); // $piaos = $this->createPiaos($betsInfos); $piaos = $this->createPiaosV2($odds, $passModeKeys, $betsNum); $piaoZhang = array_sum(array_column($piaos, 'zhang')); $order = new Order(); $order->pid = $pid; $order->customer_id = $customer->id; $order->lottery_id = $lott->id; $order->shop_id = $customer->shop_id; $order->lottery_type_id = $lott->lottery_type_id; $order->order_sn = Order::makeOrderSn(); $order->play_type = $playType; $order->bets_num = $betsNum; $order->bets_expect_num = $computeInfo['expect_bets']; $order->zhu_num = $computeInfo['zhu_num']; $order->piao_num = $piaoZhang; $order->money = $computeInfo['money']; $order->prize_min = $computeInfo['prize_min']; $order->prize_max = $computeInfo['prize_max']; $order->pay_state = PayState::UNPAID; $order->pass_mode = $passModeKeys; $order->odds_close_time = $oddsCloseTime; $order->odds_early_close_time = $earlyTime; $order->odds_late_close_time = $lateTime; $order->type = $type; $order->type_mode = $fadanSecret; $order->type_desc = $fadanDesc; $order->odds = $odds; $order->odds_raw = $oddsInfo['odds_raw']; if ($type == OrderType::UNION) { $pieceMoney = $order->money / $union_piece_total; $order->union_piece_total = $union_piece_total; $order->union_piece_buy = $union_piece_buy; $order->union_piece_self = $union_piece_buy; $order->union_piece_keep = $union_piece_keep; $order->union_keep = $union_keep; $order->union_brokerage = $union_brokerage; $order->union_piece_money = $pieceMoney; $order->union_money = $pieceMoney * ($union_piece_buy + $union_piece_keep); } $order->created_date = date('Ymd'); // 设置合作相关的数据 $order->setCooperateInfo($lott); $order->save(); // 如果是合买,更新自己的pid if ($order->type == OrderType::UNION) { $order->pid = $order->id; $order->save(); } // 创建组合数据 $betsInfos = $this->getZuheListFromPiaos($piaos); $this->createZuhe($betsInfos, $order->id, null); $orderOdds = []; foreach ($jclqOdds as $match) { $orderOdds[] = [ 'order_id' => $order->id, 'jclq_odds_id' => $match->id, 'odds_id' => $match->odds_id, 'match_id' => $match->match_id, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]; } OrderJclqResult::insert($orderOdds); DB::commit(); return $order; } catch (JingCaiException $e) { DB::rollBack(); Log::error('jclq::order::create ValidateException: ' . $e); throw $e; } catch (\Exception $e) { DB::rollBack(); Log::error('jclq::order::create Exception: ' . $e); throw $e; } } private function createZuhe($betsInfo, $orderId, $optimizeZuhe = []) { if ($optimizeZuhe) { foreach ($optimizeZuhe as $item) { $orderZuhe = new OrderLqZuhe(); $orderZuhe->order_id = $orderId; $orderZuhe->jczq_odds_ids = $item['ids']; $orderZuhe->info = $item['info']; $orderZuhe->bets_num = $item['bets_num']; $orderZuhe->repeat_num = Arr::get($item, 'repeat_num', 1); $orderZuhe->save(); } return; } foreach ($betsInfo as $item) { $orderZuhe = new OrderLqZuhe(); $orderZuhe->order_id = $orderId; $orderZuhe->jclq_odds_ids = $item['ids']; $orderZuhe->info = $item['info']; $orderZuhe->bets_num = $item['bets_num']; $orderZuhe->repeat_num = Arr::get($item, 'repeat_num', 1); $orderZuhe->save(); } } /** * 跟单 * @param $data * @param Customer $customer * @return Order * @throws \Throwable */ public function copyOrder(Customer $customer, Order $od, $data) { $betsNum = Arr::get($data, 'bets_num'); /** @var Lottery $lott */ $lott = LotteryService::getLottery($customer->shop->id, $od->lottery_type_id); throw_if(!$lott || !$lott->isActive(), JingCaiException::create('该彩种暂不支持下单!')); $jclqOdds = JclqOdds::whereIn('id', array_keys($od->odds))->get(); $closeTimes = []; /** @var JclqOdds $odd */ foreach ($jclqOdds as $odd) { $real_close_time = $odd->getCloseTime($lott->earlySecond()); $closeTimes[] = $real_close_time; } sort($closeTimes); $earlyTime = $closeTimes[0]; $lateTime = $closeTimes[count($closeTimes) - 1]; $this->checkCloseTimeOver($earlyTime); DB::beginTransaction(); try { $passModeKeys = $od->pass_mode; $oddsInfo = $this->refreshOdds($od->odds); $odds = $oddsInfo['odds']; $computeInfo = $this->computePrizeInfo($odds, $betsNum, $passModeKeys); throw_if(!bc_gte($computeInfo['money'], $lott->min_money), JingCaiException::create('最低投注' . Helps::floatFormat($lott->min_money) . '元')); // $betsInfos = $this->generateBetsInfo($odds, $passModeKeys, $betsNum); // $piaos = $this->createPiaos($betsInfos); $piaos = $this->createPiaosV2($odds, $passModeKeys, $betsNum); $piaoZhang = array_sum(array_column($piaos, 'zhang')); $order = new Order(); $order->type = OrderType::GENDAN; $order->pid = $od->id; $order->type_mode = $od->type_mode; $order->customer_id = $customer->id; $order->shop_id = $customer->shop_id; $order->lottery_id = $lott->id; $order->lottery_type_id = $lott->lottery_type_id; $order->order_sn = Order::makeOrderSn(); $order->play_type = $od->play_type; $order->odds_close_time = $od->odds_close_time; $order->odds_early_close_time = $earlyTime; $order->odds_late_close_time = $lateTime; $order->bets_num = $betsNum; $order->piao_num = $piaoZhang; $order->bets_expect_num = $computeInfo['expect_bets']; $order->zhu_num = $computeInfo['zhu_num']; $order->money = $computeInfo['money']; $order->prize_min = $computeInfo['prize_min']; $order->prize_max = $computeInfo['prize_max']; $order->pay_state = PayState::UNPAID; $order->pass_mode = $od->pass_mode; $order->odds = $odds; $order->odds_raw = $oddsInfo['odds_raw']; $order->created_date = date('Ymd'); // 设置合作相关的数据 $order->setCooperateInfo($lott); $order->save(); // 创建组合数据 $betsInfos = $this->getZuheListFromPiaos($piaos); $this->createZuhe($betsInfos, $order->id); $jclqOdds = JclqOdds::whereIn('id', array_keys($odds))->get(); $orderOdds = []; foreach ($jclqOdds as $match) { $orderOdds[] = [ 'order_id' => $order->id, 'jclq_odds_id' => $match->id, 'odds_id' => $match->odds_id, 'match_id' => $match->match_id, ]; } OrderJclqResult::insert($orderOdds); DB::commit(); return $order; } catch (JingCaiException $e) { DB::rollBack(); Log::error('jclq::order::copy ValidateException: ' . $e); throw $e; } catch (\Exception $e) { DB::rollBack(); Log::error('jclq::order::copy Exception: ' . $e); throw $e; } } /** * 展示订单详情 * @param Customer $customer 查看订单的人 * @param Order $order * @return mixed */ public function showOrder(Customer $customer, Order $order) { $order->sellings = []; // 截止后公开 if ($order->type_mode == 1 && ($order->type == OrderType::GENDAN || $order->type == OrderType::UNION)) { $isTypeModel1 = true; // 合买,是自己时,全部可见 if ($order->type == OrderType::UNION) { if ($order->customer_id == $customer->id) { $isTypeModel1 = false; } } // 跟单:如果是自己跟自己,全部可见 if ($order->type == OrderType::GENDAN) { if ($order->customer_id == $customer->id && $order->p_order->customer_id == $customer->id) { $isTypeModel1 = false; } } // 跟单:如果是自己跟自己,全部可见 if ($order->type == OrderType::FADAN) { if ($order->customer_id == $customer->id) { $isTypeModel1 = false; } } $order->sellings = $this->getOrderOdds($order, $isTypeModel1); } else { if ($order->customerCanSeeSellings($customer)) { $order->sellings = $this->getOrderOdds($order); } } if (!$order->sellings) { $odds = $order->odds; $jclqOddsIds = array_keys($odds); $jclqOdds = JclqOdds::whereIn('id', $jclqOddsIds) ->where('close_time', '>', date('Y-m-d H:i:s')) ->first(); if (!$jclqOdds) { $order->sellings = $this->getOrderOdds($order); } } $order->chang_num = count($order->sellings); $names = []; foreach ($order->pass_mode as $val) { $names[] = str_replace('.', '串', $val); } $order->pass_mode_names = $names; $order->play_name = $order->lottery->name; unset($order->lottery); return $order; } private function getOrderOdds(Order $order, $isTypeModel1 = false) { /** @var Lottery $lottery */ $lottery = $order->lottery; $earlyTime = $lottery->earlySecond(); $odds = $order->odds; $oddsIds = array_keys($odds); $jczqOdds = JclqOdds::leftJoin('jclq_match', 'jclq_match.match_id', 'jclq_odds.match_id') ->select([ 'jclq_odds.id', 'jclq_odds.issue_num', 'jclq_odds.play_num', 'jclq_odds.jc_competition_name', 'jclq_odds.jc_competition_name_full', 'jclq_odds.jc_home_team_name', 'jclq_odds.jc_home_team_name_full', 'jclq_odds.jc_away_team_name', 'jclq_odds.jc_away_team_name_full', 'jclq_odds.is_reverse', 'jclq_match.start_time', DB::raw('close_time as real_close_time'), ]) ->whereIn('jclq_odds.id', $oddsIds) ->orderBy('jclq_odds.close_time', 'asc') ->orderBy('jclq_odds.play_num', 'asc') ->get(); $currentDate = date('Y-m-d H:i:s'); $result = []; foreach ($jczqOdds as $item) { $jczqResult = null; if (in_array($order->lottery_state, Order::kaiJiangHouStates())) { $jczqResult = JclqResult::where('jclq_odds_id', $item->id)->first(); } $item->issue_num_week = JclqOdds::getIssueNumWeek($item->issue_num); $item->issue_num_day = JclqOdds::getIssueNumDay($item->issue_num); $item->vs_b = $item->jc_home_team_name; $item->vs_m = 'vs'; $item->vs_a = $item->jc_away_team_name; $item->play_items = $this->getOrderPlayItems($order, $item, $jczqResult); $item->home_score = ''; $item->away_score = ''; if ($jczqResult) { $item->home_score = $jczqResult->home_score; $item->away_score = $jczqResult->away_score; } $item->lottery_close_time = date('Y-m-d H:i:s', strtotime($item->real_close_time) - $earlyTime); $matchStartTime = $item->start_time; if (!$matchStartTime) { $matchStartTime = $item->lottery_close_time; } if ($isTypeModel1) { if ($matchStartTime > $currentDate) { $result[] = new \stdClass(); } else { $result[] = $item; } } else { $result[] = $item; } } return $result; } private function getOrderPlayItems(Order $order, $jclqOddsItem, $jczqResult) { $orderOdds = $order->odds; $oddsRaw = $order->odds_raw; $buyOddsRaw = Arr::get($oddsRaw, $jclqOddsItem->id); $buyOddsItem = Arr::get($orderOdds, $jclqOddsItem->id); $playTypeNames = $this->playTypeNames(); $result = []; foreach ($playTypeNames as $playType => $name) { $buyPlayData = Arr::get($buyOddsItem, $playType); if (!$buyPlayData) { continue; } $resultPlayTypeItem = []; foreach ($buyPlayData as $oddsField => $odds) { $wined = false; if ($playType == 'dxf_odds') { $buyScore = Arr::get($buyOddsRaw , 'dxf_odds.totalScore'); $resultTotalScore = $jczqResult ? $jczqResult->getTotalScore() : 0; $isBig = $oddsField == 'big'; if ($buyScore !== null && $isBig && bc_gt($resultTotalScore, $buyScore) ) { $wined = true; } $isSmall = $oddsField == 'small'; if ($buyScore !== null && $isSmall && bc_lt($resultTotalScore, $buyScore) ) { $wined = true; } $oddsName = $buyScore; // dump([ // '$buyPlayData' => $buyPlayData, // '$oddsField' => $oddsField, // '$odds' => $odds, // '$wined' => $wined, // '$isBig' => $isBig, // '$isSmall' => $isSmall, // '$jczqResult' => $jczqResult->toArray(), // '$buyScore' => $buyScore // // ]); } else { $oddsName = $odds; $buyField = str_replace('_odds', '_field', $playType); if ($jczqResult && $jczqResult->{$buyField} == $oddsField) { $wined = true; } } $resultPlayTypeItem[] = [ 'odds_value' => $odds, 'odds_name' => $oddsField, 'name' => sprintf('%s(%s)', $this->getResultFieldName($playType, $oddsField), $odds), 'wined' => $wined ]; } $winResult = ''; $resultField = str_replace('_odds', '_name', $playType); if ($jczqResult && $jczqResult->{$resultField}) { $winResult = $jczqResult->{$resultField}; } $buyDxf = ''; if ($playType == 'dxf_odds') { if ($jczqResult) { $winResult = $jczqResult->getTotalScore(); } if (Arr::get($buyOddsRaw, $playType . '.totalScore')) { $buyDxf = $buyOddsRaw[$playType]['totalScore']; } } else if ($playType == 'rf_odds') { if (Arr::get($buyOddsRaw, $playType . '.handicap')) { $buyDxf = $buyOddsRaw[$playType]['handicap']; if ($jczqResult) { $homeScore1 = $jczqResult->home_score; $awayScore2 = $jczqResult->away_score; $homeWin = ($homeScore1 + $buyDxf) > $awayScore2; if ($homeWin) { $winResult = '让分主胜'; } else { $winResult = '让分客胜'; } } } } $result[] = [ 'win_result' => $winResult, 'play_type' => $playType, 'play_name' => $this->getPlayTypeName($playType), 'play_name_oth' => $buyDxf, 'play_items' => $resultPlayTypeItem, ]; } return $result; } /** * 店主-展示订单详情 * @param Seller $seller 查看订单的人 * @param Order $order * @return mixed */ public function sellerShowOrder(Seller $seller, Order $order){ $order->sellings = []; if ($order->sellerCanSeeSellings($seller)) { $order->sellings = $this->getOrderOdds($order); } $order->chang_num = count($order->sellings); $names = []; foreach ($order->pass_mode as $val) { $names[] = str_replace('.', '串', $val); } $order->pass_mode_names = $names; $order->play_name = $order->lottery->name; unset($order->lottery); return $order; } public function chaiPiao(Order $order) { $betsInfo = $this->generateBetsInfo($order->odds, $order->pass_mode, $order->bets_num); // $piaos = $this->createPiaos($betsInfo); $piaos = $this->createPiaosV2($order->odds, $order->pass_mode, $order->bets_num); $piaos = $this->chaiPiaoGenV3($piaos); $jclqOdds = JclqOdds::whereIn('id', array_keys($order->odds))->pluck('rf_odds', 'id')->toArray(); $handicapList = []; foreach ($jclqOdds as $id => $item) { if ($item) { $handicapList[$id] = $item['handicap']; } } foreach ($piaos as $ind => $piao) { $piaoOddsData = []; $allBetsResultUnique=[]; foreach ($piao['bets'] as $piaoBet) { foreach ($piaoBet['info'] as $id => $idInfo) { $piaoOddsData[$id][$idInfo['play']][$idInfo['result']] = $idInfo['odd']; } @$allBetsResultUnique[$piaoBet['unique']] += $piaoBet['bets_num']; } $maxZuheList = $this->maxPrizeZuheList($piaoOddsData, $piao['pass_mode'], $handicapList); $maxPrize = 0; foreach ($maxZuheList as $zuhe) { $repeatNum = $allBetsResultUnique[$zuhe['unique']]; $maxPrize += $repeatNum * $this->getBetsInfoPrize($zuhe); } $piaos[$ind]['prize_max'] = $maxPrize; } $header = [ [ 'prop' => 'index', 'title' => '序号', ], [ 'prop' => 'type', 'title' => '过关', ], [ 'prop' => 'play_name', 'title' => $order->play_type_name, ], [ 'prop' => 'nums', 'title' => '倍数/票数', ], ]; $piaoList = []; foreach ($piaos as $k => $piao) { $buyOdds = [ ]; foreach ($piao['bets'] as $betInfo) { $piaoInfo = $betInfo['info']; foreach ($piaoInfo as $id => $info) { $buyField = $this->getResultFieldName($info['play'], $info['result']); if (!isset($buyOdds[$id])) { $buyOdds[$id] = [$buyField]; continue; } if (!in_array($buyField,$buyOdds[$id])) { $buyOdds[$id][] = $buyField; } } } $jczqOdds = JclqOdds::whereIn('id',array_keys($buyOdds)) ->get() ->keyBy('id'); $plays = []; foreach ($buyOdds as $id => $fields) { /** @var JclqOdds $oddItem */ $oddItem = Arr::get($jczqOdds, $id); $weekPlay = $oddItem->weekPlayFormat(); $plays[] = $weekPlay . ' (' . implode(' ', $fields) .')'; } if ($piao['zhang'] > 1) { $piaoMoney = $piao['zhu_money'] * 50; $beishu = 50; } else { $piaoMoney = $piao['zhu_money'] * $piao['bets_num']; $beishu = $piao['bets_num']; } $piaoList[] = [ 'header' => $header, 'data' => [ 'index' => $k +1 , 'type' => $order->pass_mode_name, 'play_name' => $plays, 'nums' => sprintf('%d倍/%d张', $beishu, $piao['zhang']) ], 'summary' => '', 'zhang' => $piao['zhang'], 'zhu_money' => $piao['zhu_money'], 'piao_money' => $piaoMoney, // 'prize_max' => Helps::floatFormat($piao['prize']/$piao['zhang']), 'prize_max' => Helps::floatFormat($piao['prize_max']), ]; } return $piaoList; } }