find($user_id); $balance = $userModel->balance ?: 0; $zoneGoodsModel = ZoneGoods::field('price')->find($zoneGoodsId); $price = $zoneGoodsModel->price ?: 0; if ($balance < $price) { return false; } return true; } /** * 出奖 * @param $user_id * @param $zone_goods_id * @param $type * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException、 */ public static function ticketing($user_id,$zone_goods_id,$type = 1) { # 获取奖项个参数 $zoneParamArr = ZoneGoodsParam::getList(['zone_goods_id' => $zone_goods_id]); if (empty($zoneParamArr)) return ['status' => 0, 'msg' => '刮奖失败']; # 获取刮刮乐信息 if ($type == 1) { $resData = self::getWinningPrize($zoneParamArr); } else { $resData = self::getWinningPrizeRandNumber($zoneParamArr); } $save_data = $resData['save_data']; $prizes_data = $resData['prizes_data'] ?? []; # 解析是否中奖,组合中奖金额 $awards_amount = 0; foreach ($save_data as $key => $goodsParam) { foreach ($goodsParam as $k => $item) { $save_data[$key][$k]['is_awards'] = 0; if (isset($item['id'])) { $awardsAmountRes = ZoneGoodsParam::getAwardsAmount($item['id']); if ($awardsAmountRes) { $save_data[$key][$k]['is_awards'] = 1; $awards_amount += $awardsAmountRes['amount']; } } } } # 处理数据返回 $data = self::handleTextData($save_data,1); # 开启事务 $connection = Db::connect(); try { $connection->startTrans(); # 扣除余额 $zoneGoodsModel = ZoneGoods::field('price')->find($zone_goods_id); $price = $zoneGoodsModel['price']; # 消费金额 $consumptionBalance = User::decrBalance($user_id,$price); # 判断是否中奖 $awards_status = 0; # 可提余额 $withdrawal_balance = 0; if ($awards_amount > 0) { $awards_status = 1; # 修改用户可提余额 $withdrawal_balance = User::incrWithdrawalBalance($user_id,$awards_amount); } # 消费订单 $c_r_id = ConsumptionRecords::saveRecords($user_id,$zone_goods_id,$price,$price,$consumptionBalance,$save_data,$prizes_data,$awards_status); if ($awards_status == 1) { # 中奖做记录 AwardsRecords::createRecords($user_id,$c_r_id,$awards_amount,$withdrawal_balance); } $connection->commit(); # 返回 刮奖数据 、 消费ID return ['status' => 1, 'data' => $data, 'c_r_id' => $c_r_id, 'prizes_data' => $prizes_data]; } catch (\Exception $e) { $connection->rollback(); return ['status' => 0, 'msg' => '操作失败']; } } /** * 刮奖完成 * @param $user_id * @param $c_r_id * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function endTicketing($user_id,$c_r_id) { # 验证 $queryWhere = ['user_id' => $user_id, 'id' => $c_r_id]; $ConsumptionRecords = new ConsumptionRecords(); $query = $ConsumptionRecords->where($queryWhere)->field('text_data,zone_goods_id,status,prizes_data')->find(); if (!$query) return ['status' => 0, 'msg' => '数据不存在']; # 解密 $data = unserialize($query['text_data']); $prizes_data = unserialize($query['prizes_data']); $returnData = self::handleTextData($data); $awards_amount = 0; $AwardsRecordsRes = AwardsRecords::where('cr_id',$c_r_id)->find(); if ($AwardsRecordsRes) $awards_amount = round($AwardsRecordsRes['awards_amount']); # 返回 刮奖数据 、 中奖号码、 中奖总金额、 中奖状态 return ['status' => 1, 'msg' => '完成', 'data' => $returnData, 'awards_amount' => $awards_amount, 'prizes_data' => $prizes_data]; } /** * 余额扣减后 生成订单 * @param $user_id * @param $zone_goods_id * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function createOrder($user_id,$zone_goods_id) { # 判断用户是否存在未刮的 $inspect = self::inspectCompleteRecord($user_id); if ($inspect['status']) { return $inspect; } # 获取奖项个参数 $zoneParamArr = ZoneGoodsParam::getList(['zone_goods_id' => $zone_goods_id]); if (empty($zoneParamArr)) return ['status' => 0, 'msg' => '刮奖失败']; # 获取刮刮乐信息 $resData = self::getWinningPrize($zoneParamArr); $data = $resData['data']; $save_data = $resData['save_data']; # 开启事务 $connection = Db::connect(); try { $connection->startTrans(); # 扣除余额 $zoneGoodsModel = ZoneGoods::field('price')->find($zone_goods_id); $price = $zoneGoodsModel['price']; $balance = User::decrBalance($user_id,$price); # 消费记录 $c_r_id = ConsumptionRecords::createRecords($user_id,$zone_goods_id,$price,$price,$balance,$save_data); $connection->commit(); # 返回刮刮乐图标、金额、订单id return ['status' => 1, 'data' => $data, 'c_r_id' => $c_r_id]; } catch (\Exception $e) { $connection->rollback(); return ['status' => 0, 'msg' => '操作失败']; } } /** * 刮奖完成 * @param $user_id * @param $c_r_id * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function endOrder($user_id,$c_r_id) { # 验证 $queryWhere = ['user_id' => $user_id, 'id' => $c_r_id]; $ConsumptionRecords = new ConsumptionRecords(); $query = $ConsumptionRecords->where($queryWhere)->field('text_data,zone_goods_id,status')->find(); if (!$query) return ['status' => 0, 'msg' => '数据不存在']; if ($query['status'] == 1) return ['status' => 0, 'msg' => '刮奖结果已公布']; # 解密 $data = unserialize($query['text_data']); # 解析是否中奖 $awards_amount = 0; foreach ($data as $key => $goodsParam) { foreach ($goodsParam as $k => $item) { $data[$key][$k]['is_awards'] = 0; if (isset($item['id'])) { $awardsAmountRes = ZoneGoodsParam::getAwardsAmount($item['id']); if ($awardsAmountRes) { $data[$key][$k]['is_awards'] = 1; $awards_amount += $awardsAmountRes['amount']; } } } } $returnData = self::handleTextData($data); $ConsumptionRecords->awardsData($data,$c_r_id); # 开启事务 $connection = Db::connect(); try { $connection->startTrans(); # 判断是否中奖 if ($awards_amount > 0) { # 修改用户余额 $balance = User::incrWithdrawalBalance($user_id,$awards_amount); # 中奖做记录 AwardsRecords::createRecords($user_id,$c_r_id,$awards_amount,$balance); } # 完成订单 ConsumptionRecords::endOrder($c_r_id,$awards_amount); $connection->commit(); return ['status' => 1, 'msg' => '完成', 'awards_amount' => $awards_amount, 'data' => $returnData]; } catch (\Exception $e) { $connection->rollback(); return ['status' => 0, 'msg' => '操作异常']; } } /** * 检查用户是否存在未刮的 * @param $user_id * @return array|int[] * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function inspectCompleteRecord($user_id) { $query = ConsumptionRecords::where(['user_id' => $user_id,'status' => 0])->find(); if ($query) { $data = self::handleTextData(unserialize($query['text_data'])); return ['status' => 1, 'data' => $data, 'c_r_id' => $query['id']]; }; return ['status' => 0]; } /** * 处理刮奖信息数据 * @param $data * @param $is_awards // 1-删除 0-不删 * @return mixed */ public static function handleTextData($data,$is_awards = 0) { foreach ($data as $key => $value) { foreach ($value as $k => $v) { #$data[$key][$k]['amount'] = rtrim($v['amount'],'.00'); unset($data[$key][$k]['id']); if ($is_awards) { unset($data[$key][$k]['is_awards']); } } } return $data; } /** * 获取刮刮乐信息(概率算法 - 自定义中奖图片 - 获取随机无奖图片) * @param array $patterns // 数据 和 占比 * @param int $direction // 纵向数量 * @param int $transverse // 横向数量 * @return array[] */ public static function getWinningPrize(array $patterns,int $direction = 3,int $transverse = 4) { // $patterns = [ // ['image' => 'prize1.png', 'probability' => 0.3], // 奖项图案,概率为30% // ['image' => 'prize2.png', 'probability' => 0.2], // 奖项图案,概率为20% // ['image' => 'no_prize1.png', 'probability' => 0.1], // 奖项图案,概率为10% // ['image' => 'no_prize2.png', 'probability' => 0.32], // 奖项图案,概率为32% // ['image' => 'test1.png', 'probability' => 0.07], // 奖项图案,概率为7% // ['image' => 'test2.png', 'probability' => 0.002], // 奖项图案,概率为0.2% // ['image' => 'test3.png', 'probability' => 0.003], // 奖项图案,概率为0.3% // ['image' => 'test4.png', 'probability' => 0.004], // 奖项图案,概率为0.4% // ['image' => 'test5.png', 'probability' => 0.001], // 奖项图案,概率为0.1% // ]; // 计算概率总和 $totalProbability = 0; foreach ($patterns as $pattern) { $totalProbability += $pattern['probability']; } // 归一化处理,并计算累积概率 $accumulatedProbability = 0; foreach ($patterns as &$pattern) { $pattern['probability'] /= $totalProbability; // 归一化处理 $accumulatedProbability += $pattern['probability']; $pattern['accumulatedProbability'] = $accumulatedProbability; // 累积概率 } unset($pattern); $data = []; $save_data = []; for ($i = 0; $i < $direction; $i++) { for ($j = 0; $j < $transverse; $j++) { // 每组生成 3 个图案 $selectedPattern = null; $randomNumber = mt_rand() / mt_getrandmax(); // 生成 0 到 1 之间的随机数 foreach ($patterns as $pattern) { if ($randomNumber <= $pattern['accumulatedProbability']) { $selectedPattern = $pattern; break; } } $amount = round($selectedPattern['amount']); $pinyin = PinyinNumber::getPinyin($amount,true); $amount_format = number_format($amount); $image_url = get_image_url($selectedPattern['image']); $data[$i][] = [ 'amount' => $amount_format, 'pinyin' => $pinyin, 'image' => $image_url ]; $save_data[$i][] = [ 'id' => $selectedPattern['id'], 'amount' => $amount_format, 'pinyin' => $pinyin, 'image' => $image_url ]; } } return [ 'data' => $data, 'save_data' => $save_data ]; } /** * 获取刮刮乐信息(概率算法 - 随机中奖数字图片 随机无奖数字图片) * @param array $patterns // 数据 和 占比 * @param int $direction // 纵向数量 * @param int $transverse // 横向数量 * @param int $randNum // 中奖号码数量 * @return array[] */ public static function getWinningPrizeRandNumber(array $patterns,int $direction = 3,int $transverse = 4, int $randNum = 3) { # 中奖号码 $prizesFiles = []; # 有奖号码图片 # 获取数字图片 $noPrizeFiles = return_image_name('number_icon'); # 无奖号码图片 # 获取随机中奖数字 踢出所在数组 for ($i = 1; $i <= $randNum; $i++) { $rand = rand(0,count($noPrizeFiles)-1); $prizesFiles[] = $noPrizeFiles[$rand]; unset($noPrizeFiles[$rand]); sort($noPrizeFiles); } $noPrizeCount = count($noPrizeFiles); // 计算概率总和 $totalProbability = 0; foreach ($patterns as $pattern) { $totalProbability += $pattern['probability']; } // 归一化处理,并计算累积概率 $accumulatedProbability = 0; foreach ($patterns as &$pattern) { $pattern['probability'] /= $totalProbability; // 归一化处理 $accumulatedProbability += $pattern['probability']; $pattern['accumulatedProbability'] = $accumulatedProbability; // 累积概率 } unset($pattern); $data = []; $save_data = []; for ($i = 0; $i < $direction; $i++) { for ($j = 0; $j < $transverse; $j++) { // 每组生成 3 个图案 $selectedPattern = null; $randomNumber = mt_rand() / mt_getrandmax(); // 生成 0 到 1 之间的随机数 foreach ($patterns as $pattern) { if ($randomNumber <= $pattern['accumulatedProbability']) { $selectedPattern = $pattern; break; } } # 新逻辑 数字图片 if ($selectedPattern['awards'] == '1') { $tempRand = rand(0,$randNum -1); $numberImage = $prizesFiles[$tempRand]; } else { $tempRand = rand(0,$noPrizeCount - 1); $numberImage = $noPrizeFiles[$tempRand]; } $numberImage = get_image_url($numberImage); # 金额拼音 $amount = round($selectedPattern['amount']); $pinyin = PinyinNumber::getPinyin($amount,true); $amount_format = number_format($amount); # 返回给用户数据 $data[$i][] = [ 'amount' => $amount_format, 'pinyin' => $pinyin, 'image' => $numberImage ]; # 保存到系统数据 $save_data[$i][] = [ 'id' => $selectedPattern['id'], 'amount' => $amount_format, 'pinyin' => $pinyin, 'image' => $numberImage ]; } } # 返回中奖图片地址 foreach ($prizesFiles as &$valFiles) { $valFiles = get_image_url($valFiles); } return [ 'data' => $data, 'save_data' => $save_data, 'prizes_data' => $prizesFiles ]; } /** * 自动刮奖测试机 * @param $user_id * @param $zone_goods_id * @param $count * @return string|void * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function auto($user_id = 1,$zone_goods_id = 1,$count = 500) { # 验证 $user = User::find($user_id); if (!$user) return '用户不存在'; $zoneGoods = ZoneGoods::find($zone_goods_id); if (!$zoneGoods) return '刮奖商品不存在'; $zoneGoodsParam = ZoneGoodsParam::where('zone_goods_id',$zone_goods_id)->where('status',1)->find(); if (!$zoneGoodsParam) return '刮奖奖项不存在'; $balance = $user->balance ?: 0; $sumPrice = $count * $zoneGoods['price']; if ($balance < $sumPrice) return '用户余额不足'; # 开始执行 $limit = 1; while ($limit <= $count) { $result = self::ticketing($user_id,$zone_goods_id,2); if (!$result['status']) return $result['msg']; // # 获取奖项个参数 // $zoneParamArr = ZoneGoodsParam::getList(['zone_goods_id' => $zone_goods_id]); // if (empty($zoneParamArr)) return '奖项不存在'; // // # 获取刮刮乐信息 // $resData = Zone::getWinningPrize($zoneParamArr); // #$data = $resData['data']; // $save_data = $resData['save_data']; // // # 开启事务 // $connection = Db::connect(); // try { // // $connection->startTrans(); // // # 扣除余额 // $zoneGoodsModel = ZoneGoods::field('price')->find($zone_goods_id); // $price = $zoneGoodsModel['price']; // $balance = User::decrBalance($user_id,$price); // // # 消费记录 // $c_r_id = ConsumptionRecords::createRecords($user_id,$zone_goods_id,$price,$price,$balance,$save_data); // // # 解析是否中奖 // $awards_amount = 0; // foreach ($save_data as $key => $goodsParam) { // foreach ($goodsParam as $k => $item) { // $save_data[$key][$k]['is_awards'] = 0; // if (isset($item['id'])) { // $awardsAmountRes = ZoneGoodsParam::getAwardsAmount($item['id']); // if ($awardsAmountRes) { // $save_data[$key][$k]['is_awards'] = 1; // $awards_amount += $item['amount']; // } // } // } // } // // $ConsumptionRecords = new ConsumptionRecords(); // // $ConsumptionRecords::awardsData($save_data,$c_r_id); // // # 判断是否中奖 // if ($awards_amount > 0) { // // # 修改用户余额 // $balance = User::incrWithdrawalBalance($user_id,$awards_amount); // // # 中奖做记录 // AwardsRecords::createRecords($user_id,$c_r_id,$awards_amount,$balance); // } // // # 完成订单 // ConsumptionRecords::endOrder($c_r_id,$awards_amount); // // $connection->commit(); // // # 返回刮刮乐图标、金额、订单id // } catch (\Exception $e) { // // $connection->rollback(); // return $e->getMessage(); // } # 循环执行 $limit++; } return '完成'; } }