notEmpty()->setName(trans('phone', [], 'message'))) ->key('type', v::in([1, 2])->notEmpty()->setName(trans('type', [], 'message'))) ->key('code', v::stringType()->setName(trans('code', [], 'message')), false) ->key('password', v::stringType()->setName(trans('password', [], 'message')), false); $data = $request->all(); try { $validator->assert($data); //手机号规则 if(!validateMalaysianPhoneNumber($data['phone'])){ throw new Exception(trans('phone_val_error', [], 'message')); } $pattern = '/(\+60|60|0060)01\d{8,9}/'; if (preg_match($pattern, $data['phone'])) { $data['phone'] = substr_replace($data['phone'], '601', 0, 4); } /** @var Player $player */ $player = Player::where('phone', $data['phone']) ->where('department_id', request()->department_id) ->first(); if(empty($player)){ throw new Exception(trans('player_not_found', [], 'message')); } //密码登录 if($data['type'] == 1){ if(!isset($data['password']) || !password_verify($data['password'],$player->password)){ throw new Exception(trans('password_error', [], 'message')); } }else{ //验证码错误 $phone_code = Redis::get(setSmsKey($data['phone'], PhoneSmsLog::TYPE_LOGIN)); if(!$phone_code){ throw new Exception(trans('phone_sms_expire', [], 'message')); } if(!isset($data['code']) || empty($data['code']) || $phone_code != $data['code']){ throw new Exception(trans('phone_sms_error', [], 'message')); } } if ($player->status == Player::STATUS_STOP) { throw new Exception(trans('account_stop', [], 'message')); } $player->last_login = date('Y-m-d H:i:s'); addLoginRecord($player->id); } catch (AllOfException $e) { throw new Exception(getValidationMessages($e)); } catch (Exception $e) { throw new Exception($e->getMessage()); } return jsonSuccessResponse('success', [ 'token' => JwtToken::generateToken([ 'id' => $player->id, 'avatar' => $player->avatar, 'name' => $player->name, 'type' => $player->type, 'currency' => $player->currency, 'recommended_code' => $player->recommended_code, ]), ]); } /** * 手机号注册 * @param Request $request * @return Response * @throws Exception */ public function phoneRegister(Request $request): Response { $data = $request->all(); $validator = v::key('phone', v::stringType()->notEmpty()->setName(trans('phone', [], 'message'))) ->key('code', v::stringType()->setName(trans('code', [], 'message'))) ->key('password', v::stringType()->setName(trans('password', [], 'message'))) ->key('confim_password', v::stringType()->setName(trans('confim_password', [], 'message'))) ->key('nickname', v::stringType()->setName(trans('nickname', [], 'message'))); try { $validator->assert($data); //网页注册 if(!empty($data['web_register']) && empty($data['recommended_code'])){ throw new Exception(trans('recommend_player_not_found', [], 'message')); } //手机号规则 if(!validateMalaysianPhoneNumber($data['phone'])){ throw new Exception(trans('phone_val_error', [], 'message')); } $pattern = '/(\+60|60|0060)01\d{8,9}/'; if (preg_match($pattern, $data['phone'])) { $data['phone'] = substr_replace($data['phone'], '601', 0, 4); } //两次密码不一致 if($data['password'] != $data['confim_password']){ throw new Exception(trans('confim_password_differ', [], 'message')); } //验证码错误 $phone_code = Redis::get(setSmsKey($data['phone'], PhoneSmsLog::TYPE_REGISTER)); if(!$phone_code){ throw new Exception(trans('phone_sms_expire', [], 'message')); } if(!isset($data['code']) || empty($data['code']) || $phone_code != $data['code']){ throw new Exception(trans('phone_sms_error', [], 'message')); } /** @var Player $player */ $player = Player::where('phone', $data['phone']) ->where('department_id', request()->department_id) ->first(); //手机号已被注册 if($player){ throw new Exception(trans('phone_has_registered', [], 'message')); } $create_player['phone'] = $data['phone']; $create_player['password'] = $data['password']; $create_player['name'] = $data['nickname']; $player = createPlayer(request()->department_id,$create_player); } catch (AllOfException $e) { throw new Exception(getValidationMessages($e)); } catch (Exception $e) { throw new Exception(trans('create_player_fail', [], 'message') . $e->getMessage()); } return jsonSuccessResponse('success', [ 'token' => JwtToken::generateToken([ 'id' => $player->id, 'avatar' => $player->avatar, 'name' => $player->name, 'type' => $player->type, 'currency' => $player->currency, 'recommended_code' => $player->recommended_code, ]), ]); } /** * 忘记密码 * @param Request $request * @return Response * @throws \Exception */ public function forgetPassword(Request $request): Response { $data = $request->all(); $validator = v::key('phone', v::stringType()->notEmpty()->setName(trans('phone', [], 'message'))) ->key('code', v::stringType()->setName(trans('code', [], 'message'))) ->key('password', v::stringType()->setName(trans('password', [], 'message'))) ->key('confim_password', v::stringType()->setName(trans('confim_password', [], 'message'))); try { $validator->assert($data); //手机号规则 if(!validateMalaysianPhoneNumber($data['phone'])){ throw new Exception(trans('phone_val_error', [], 'message')); } $pattern = '/(\+60|60|0060)01\d{8,9}/'; if (preg_match($pattern, $data['phone'])) { $data['phone'] = substr_replace($data['phone'], '601', 0, 4); } //两次密码不一致 if($data['password'] != $data['confim_password']){ throw new Exception(trans('confim_password_differ', [], 'message')); } //验证码错误 $phone_code = Redis::get(setSmsKey($data['phone'], PhoneSmsLog::TYPE_CHANGE_PASSWORD)); if(!$phone_code){ throw new Exception(trans('phone_sms_expire', [], 'message')); } if(!isset($data['code']) || empty($data['code']) || $phone_code != $data['code']){ throw new Exception(trans('phone_sms_error', [], 'message')); } /** @var Player $player */ $player = Player::where('phone', $data['phone']) ->where('department_id', request()->department_id) ->first(); if(empty($player)){ throw new Exception(trans('player_not_found', [], 'message')); } $player->password = $data['password']; $player->push(); } catch (AllOfException $e) { throw new Exception(getValidationMessages($e)); } catch (Exception $e) { throw new Exception($e->getMessage()); } return jsonSuccessResponse(trans('password_revise_suc', [], 'message')); } /** * 发送验证码 * @param Request $request * @return Response * @throws \Exception */ public function sendMsg(Request $request): Response { $data = $request->all(); $validator = v::key('phone', v::stringType()->notEmpty()->setName(trans('phone', [], 'message'))) ->key('type', v::stringType()->setName(trans('type', [], 'message')), false); try { $validator->assert($data); //手机号规则 if(!validateMalaysianPhoneNumber($data['phone'])){ throw new Exception(trans('phone_val_error', [], 'message')); } $pattern = '/(\+60|60|0060)01\d{8,9}/'; if (preg_match($pattern, $data['phone'])) { $data['phone'] = substr_replace($data['phone'], '601', 0, 4); } if ($data['type'] == 1 || $data['type'] == 3) { $player = Player::query()->where('phone', $data['phone'])->first(); if(empty($player)){ throw new Exception(trans('player_not_found', [], 'message')); } } $env = config('app.env'); $config = config('sms'); $code = ($env == 'pro' ? random_int(10000, 99999) : config('sms.default_code')); //发送验证码 $params = [ "userId" => $config['userId'], "account"=> $config['account'], "password"=> $config['password'], "mobile"=> $data['phone'], "content"=> '【Samsung88】您的验证码为'.$code.',5分钟内有效。', "sendTime"=> "", "action"=> "sendhy", "custom"=> "1" ]; $result = doCurl($config['aliwy_url'], $params); if($result['code'] == 200 && $result['data']['status'] == 'Success'){ $key = setSmsKey($data['phone'], $data['type']); $phoneSmsLog = new PhoneSmsLog(); $phoneSmsLog->player_id = isset($data['player_id']) ? $data['player_id'] : 0; $phoneSmsLog->code = $code; $phoneSmsLog->phone = $data['phone']; $phoneSmsLog->send_times = 1; $phoneSmsLog->type = $data['type']; $phoneSmsLog->expire_time = date("Y-m-d H:i:s", time() + 300); $phoneSmsLog->response = $result ? json_encode($result) : ''; Redis::set($key, $code, 'EX', 300); $phoneSmsLog->status = 1; $phoneSmsLog->save(); }else{ throw new Exception($result['data']['message']); } } catch (AllOfException $e) { throw new Exception(getValidationMessages($e)); }catch (Exception $e) { throw new Exception($e->getMessage()); } return jsonSuccessResponse(trans('phone_sms_send_success', [], 'message')); } /** * 获取用户信息 * @param Request $request * @return Response * @throws GameException * @throws PlayerCheckException */ public function playerInfo(Request $request): Response { $player = checkPlayer(); $prizes = Prize::query() ->select('pic', 'name', 'id', 'type') ->where('department_id', $player->department_id) ->where('status', 1) ->orderBy('probability') ->get() ->toArray(); $game = Game::query()->select('description', 'game_url')->first(); return jsonSuccessResponse('success', [ 'id' => $player->id, 'phone' => $player->phone, 'avatar' => $player->avatar, 'currency' => $player->currency, 'uuid' => $player->uuid, 'money' => $player->wallet->money, 'name' => $player->name, 'recharge_amount' => $player->player_extend->recharge_amount ?? 0, 'game_description' => $game->description, 'game_url' => $game->game_url, 'prize_list' => $prizes, 'bank_list' => PlayerBank::query() ->select('id', 'bank_name', 'account', 'account_name', 'bank_code') ->where('player_id', $player->id) ->where('status', 1) ->where('pay_type', '!=', 4) ->get(), 'usdt' => PlayerBank::query() ->select('id', 'wallet_address', 'qr_code') ->where('player_id', $player->id) ->where('status', 1) ->where('pay_type', 4) ->first(), 'whats_app' => Channel::query()->where('department_id', $player->department_id)->value('telegram_url'), ]); } /** * 获取充值列表 * @return Response * @throws PlayerCheckException|GameException */ public function rechargeList(): Response { $player = checkPlayer(); $lang = locale(); $lang = Str::replace('_', '-', $lang); $channelRechargeMethod = ChannelRechargeMethod::query() ->with(['methodLang' => function ($query) use ($lang) { $query->select(['id', 'bank_name', 'sub_bank', 'owner', 'name', 'method_id', 'lang'])->where('lang', $lang); }]) ->where('status', 1) ->where('department_id', $player->department_id) ->orderBy('created_at', 'desc') ->select(['id', 'account', 'currency']) ->get(); $list = []; /** @var ChannelRechargeMethod $item */ foreach ($channelRechargeMethod as $item) { $list[] = [ 'id' => $item->id, 'account' => $item->account, 'currency' => $item->currency, 'name' => $item->methodLang[0]['name'] ?? '', 'bank_name' => $item->methodLang[0]['bank_name'] ?? '', 'sub_bank' => $item->methodLang[0]['sub_bank'] ?? '', 'owner' => $item->methodLang[0]['sub_bank'] ?? '', ]; } return jsonSuccessResponse('success', [ 'list' => $list, ]); } /** * 获取充值项列表 * @param Request $request * @return Response * @throws PlayerCheckException|GameException */ public function rechargeSettingList(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('method_id', v::oneOf(v::intVal(), v::equals(''))->setName(trans('method_id', [], 'message')), false) ->key('setting_id', v::oneOf(v::intVal(), v::equals(''))->setName(trans('setting_id', [], 'message')), false) ->key('type', v::in([ChannelRechargeSetting::TYPE_REGULAR, ChannelRechargeSetting::TYPE_ACTIVITY, ''])->setName(trans('recharge_type', [], 'message')), false); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } $list = ChannelRechargeSetting::query() ->whereHas('channel_recharge_method', function ($query) { $query->where('status', 1); }) ->when(!empty($data['method_id']), function ($query) use ($data) { $query->where('method_id', $data['method_id']); }) ->when(!empty($data['setting_id']), function ($query) use ($data) { $query->where('id', $data['setting_id']); }) ->when(!empty($data['type']), function ($query) use ($data) { $query->where('type', $data['type']); }) ->where('department_id', $player->department_id) ->where('status', 1) ->orderBy('coins_num', 'asc') ->select(['id', 'title', 'chip_multiple', 'coins_num', 'money', 'type', 'method_id']) ->get(); return jsonSuccessResponse('success', [ 'list' => $list, ]); } /** * 充值详情 * @param Request $request * @return Response * @throws PlayerCheckException|GameException */ public function rechargeInfo(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('id', v::intVal()->notEmpty()->setName(trans('recharge_id', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } $lang = locale(); $lang = Str::replace('_', '-', $lang); /** @var ChannelRechargeSetting $recharge */ $recharge = ChannelRechargeSetting::query() ->with(['channel_recharge_method' => function ($query) use ($lang) { $query->select(['id', 'account', 'currency'])->with(['methodLang' => function ($query) use ($lang) { $query->select(['id', 'bank_name', 'sub_bank', 'owner', 'name', 'method_id', 'lang'])->where('lang', $lang); }]); }]) ->where('department_id', $player->department_id) ->where('id', $data['id']) ->select(['id', 'title', 'chip_multiple', 'coins_num', 'gift_coins', 'money', 'type', 'method_id', 'status']) ->first(); if (!$recharge) { return jsonFailResponse(trans('recharge_setting_not_found', [], 'message')); } if ($recharge->status == 0) { return jsonFailResponse(trans('recharge_setting_disabled', [], 'message')); } return jsonSuccessResponse(trans('success', [], 'message'), [ 'recharge_setting' => $recharge ]); } /** * 编辑玩家名称 * @param Request $request * @return Response * @throws PlayerCheckException|GameException */ public function editPlayerName(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('player_name', v::stringVal()->length(1, 50)->setName(trans('player_name', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } if (Player::withTrashed()->where('name', $data['player_name'])->where('id', '!=', $player->id)->exists()) { return jsonFailResponse(trans('player_name_has_exist', [], 'message')); } $player->name = $data['player_name'] ?? ''; $player->save(); return jsonSuccessResponse('success'); } /** * 數據中心 * @return Response * @throws PlayerCheckException|GameException */ public function giftCenter(): Response { $player = checkPlayer(); return jsonSuccessResponse('success', [ 'chip_amount' => $player->chip_amount, 'must_chip_amount' => $player->must_chip_amount, 'coins' => $player->wallet->money, ]); } /** * 获取四方充值列表 * @return Response * @throws PlayerCheckException|GameException */ public function seRechargeList(): Response { $player = checkPlayer(false); $list = SepayRecharge::query()->where('department_id', $player->department_id) ->where('status', 1) ->orderBy('money') ->select(['id', 'title', 'coins_num', 'gift_coins', 'first_coins', 'money']) ->get()->toArray(); $time = date('H:i:s'); foreach ($list as &$value){ $value['P2PDEPOSIT'] = 0; $value['DUITNOWP2P'] = 0; if ($value['money'] >= 5 && $value['money'] <= 1000) { $value['P2PDEPOSIT'] = 1; if ($time >= '23:50:00' || $time <= '01:05:00') { $value['P2PDEPOSIT'] = 0; } } if ($value['money'] >= 30 && $value['money'] <= 20000) { $value['DUITNOWP2P'] = 1; } $firstRecharge = PlayerRechargeRecord::query() ->where('player_id', $player->id) ->where('status', 2) ->where('setting_id', $value['id']) ->first(); if ($firstRecharge) { $value['first_coins'] = '0.00'; } } unset($value); $bankList = []; $bankSelect = 0; if (in_array($player->channel->pay_type, [2, 3])) { $bankSelect = 1; $bankList = BankList::query() ->select(['bank_name', 'bank_code']) ->where('pay_type', $player->channel->pay_type) ->where('type', 1) ->whereNull('deleted_at') ->get() ->toArray(); } $rechargeSetting = ChannelRechargeMethod::query() ->with('methodLang') ->select(['id', 'account', 'wallet_address', 'qr_code', 'type']) ->where('department_id', $player->department_id) ->where('status', 1) ->get()->toArray(); foreach ($rechargeSetting as &$item) { if ($item['type'] == 1) { $item['name'] = 'artificial'; } else { $item['name'] = 'usdt'; } } unset($item); $rechargeSetting[] = [ 'name' => 'SKL', 'type' => 3, ]; return jsonSuccessResponse('success', [ 'list' => $list, 'bank_select' => $bankSelect, 'bank_list' => $bankList, 'recharge_setting' => $rechargeSetting ]); } /** * 玩家充值 * @param Request $request * @return Response * @throws PlayerCheckException * @throws GameException */ public function seRecharge(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('amount', v::notEmpty()->intVal()->setName(trans('recharge_amount', [], 'message'))) ->key('type', v::notEmpty()->intVal()->setName(trans('type', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } /** @var Channel $channel */ $channel = Channel::where('department_id', $player->department_id)->first(); if (empty($channel)) { return jsonFailResponse(trans('channel_not_found', [], 'message')); } /** @var SepayRecharge $sepayInfo */ $sepayInfo = SepayRecharge::query()->where('department_id', $player->department_id) ->where('money', $data['amount'])->first(); $firstCoins = 0; $allCoins = $data['amount']; if(!empty($sepayInfo)) { if ($sepayInfo->first_coins > 0) { $firstRecharge = PlayerRechargeRecord::query() ->where('player_id', $player->id) ->where('status', 2) ->where('setting_id', $sepayInfo->id) ->doesntExist(); if ($firstRecharge) { $firstCoins = $sepayInfo->first_coins; } } $allCoins = bcadd($sepayInfo->coins_num, $firstCoins, 2); } $orderNo = createOrderNo(); // 生成充值订单 $playerRechargeRecord = new PlayerRechargeRecord(); $playerRechargeRecord->player_id = $player->id; $playerRechargeRecord->department_id = $player->department_id; $playerRechargeRecord->tradeno = $orderNo; $playerRechargeRecord->player_name = $player->name ?? ''; $playerRechargeRecord->money = $data['amount']; $playerRechargeRecord->inmoney = $data['amount']; $playerRechargeRecord->setting_id = $sepayInfo->id ?? 0; $playerRechargeRecord->coins = $data['amount']; $playerRechargeRecord->gift_coins = $firstCoins; $playerRechargeRecord->currency = 'RM'; //手动支付 if ($data['type'] == 1) { $playerRechargeRecord->type = PlayerRechargeRecord::TYPE_REGULAR; $playerRechargeRecord->status = PlayerRechargeRecord::STATUS_WAIT; $playerRechargeRecord->save(); //USDT支付 } elseif ($data['type'] == 2) { $rate = ChannelRechargeMethod::query() ->where('department_id', $player->department_id) ->where('type', 2) ->value('rate'); $playerRechargeRecord->rate = $rate; $playerRechargeRecord->currency = 'USDT'; $playerRechargeRecord->type = PlayerRechargeRecord::TYPE_REGULAR; $playerRechargeRecord->status = PlayerRechargeRecord::STATUS_WAIT; $playerRechargeRecord->save(); //三方支付 }elseif ($data['type'] == 3) { if ($data['payment_code'] == 'DUITNOWP2P') { $paymentCode = 'QR'; } else { $paymentCode = $data['bank_code']; } $params = [ 'amount' => $data['amount'], 'paymentCode' => $paymentCode, 'name' => 'ggl-ds ' . $player->uuid, 'orderNo' => $orderNo, ]; $res = (new SklPayServices())->deposit($params); if (!isset($res['status']) && empty($res['code'])) { DB::beginTransaction(); try { $pay_url = $res['transaction_link']; $playerRechargeRecord->payment_method = $params['paymentCode'] == 'QR' ? 'QR' : 'P2P'; $playerRechargeRecord->external_reference = $res['transaction_id']; $playerRechargeRecord->type = PlayerRechargeRecord::TYPE_REGULAR; $playerRechargeRecord->status = PlayerRechargeRecord::STATUS_WAIT; $playerRechargeRecord->remark = 'SKL99'; $playerRechargeRecord->save(); DB::commit(); } catch (\Exception $e) { DB::rollBack(); return jsonFailResponse($e->getMessage()); } return jsonSuccessResponse('success', ['pay_url' => $pay_url]); } else { return jsonFailResponse($res['error']); } } sendSocketMessage('private-admin_group-channel-' . request()->department_id, [ 'msg_type' => 'player_examine_recharge_order', 'id' => $playerRechargeRecord->id, 'player_id' => $player->id, 'player_name' => $player->name, 'player_phone' => $player->phone, 'money' => $playerRechargeRecord->money, 'status' => $playerRechargeRecord->status, 'tradeno' => $playerRechargeRecord->tradeno, ]); $rechargeSetting = ChannelRechargeMethod::query() ->with('methodLang') ->select(['id', 'account', 'wallet_address', 'qr_code', 'type']) ->where('department_id', $player->department_id) ->where('status', 1) ->where('type', $data['type']) ->get()->toArray(); return jsonSuccessResponse('success', [ 'tradeno' => $playerRechargeRecord->tradeno, 'order_id' => $playerRechargeRecord->id, 'money' => $playerRechargeRecord->money, 'coins' => $allCoins, 'currency' => $playerRechargeRecord->currency, 'status' => $playerRechargeRecord->status, 'created_at' => strtotime($playerRechargeRecord->created_at), 'recharge_setting' => $rechargeSetting ]); } /** * 完成充值 * @param Request $request * @return Response * @throws PlayerCheckException * @throws PushException|GameException */ public function completeRecharge(Request $request): Response { $player = checkPlayer(); $data = $request->post(); $validator = v::key('id', v::notEmpty()->intVal()->setName(trans('recharge_record_id', [], 'message'))) ->key('certificate', v::notEmpty()->stringVal()->setName(trans('certificate', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } /** @var PlayerRechargeRecord $rechargeRecord */ $rechargeRecord = PlayerRechargeRecord::query() ->where('player_id', $player->id) ->where('id', $data['id']) ->first(); if (empty($rechargeRecord)) { return jsonFailResponse(trans('recharge_record_not_found', [], 'message')); } switch ($rechargeRecord->status) { case PlayerRechargeRecord::STATUS_RECHARGING: return jsonFailResponse(trans('recharge_record_review_in_progress', [], 'message')); case PlayerRechargeRecord::STATUS_RECHARGED_SUCCESS: return jsonFailResponse(trans('recharge_completed', [], 'message')); case PlayerRechargeRecord::STATUS_RECHARGED_FAIL: return jsonFailResponse(trans('recharge_failed', [], 'message')); case PlayerRechargeRecord::STATUS_RECHARGED_CANCEL: return jsonFailResponse(trans('player_has_cancelled_recharge', [], 'message')); case PlayerRechargeRecord::STATUS_RECHARGED_REJECT: return jsonFailResponse(trans('recharge_order_review_failed', [], 'message')); case PlayerRechargeRecord::STATUS_RECHARGED_SYSTEM_CANCEL: return jsonFailResponse(trans('system_cancels_order', [], 'message')); } $rechargeRecord->status = PlayerRechargeRecord::STATUS_RECHARGING; $rechargeRecord->certificate = $data['certificate']; $rechargeRecord->save(); sendSocketMessage('private-admin_group-channel-' . $player->department_id, [ 'msg_type' => 'player_examine_recharge_order', 'id' => $rechargeRecord->id, 'player_id' => $player->id, 'player_name' => $player->name, 'player_phone' => $player->phone, 'money' => $rechargeRecord->money, 'status' => $rechargeRecord->status, 'tradeno' => $rechargeRecord->tradeno, ]); return jsonSuccessResponse('success'); } /** * 玩家提现 * @param Request $request * @return Response * @throws PlayerCheckException * @throws GameException */ public function seWithdrawal(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('amount', v::intVal()->notEmpty()->min(100)->max(20000)->setName(trans('withdrawal_amount', [], 'message'))) ->key('bank_id', v::intVal()->setName(trans('withdrawal_bank', [], 'message'))) ->key('type', v::intVal()->setName(trans('type', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } /** @var Channel $channel */ $channel = Channel::where('department_id', $player->department_id)->first(); if ($player->status_withdraw != 1) { return jsonFailResponse(trans('player_withdraw_closed', [], 'message')); } if ($player->wallet->money < $data['amount']) { return jsonFailResponse(trans('insufficient_balance', [], 'message')); } if ($channel->withdraw_status == 0) { return jsonFailResponse(trans('self_withdraw_closed', [], 'message')); } if (empty($data['bank_id'])) { return jsonFailResponse(trans('please_select_player_bank', [], 'message')); } /** @var Currency $currency */ $currency = Currency::where('identifying', $channel->currency)->where('status', 1)->whereNull('deleted_at')->first(); if (empty($currency)) { return jsonFailResponse(trans('currency_no_setting', [], 'message')); } /** @var PlayerBank $playerBank */ $playerBank = PlayerBank::where('id', $data['bank_id']) ->where('player_id', $player->id) ->where('status', 1) ->whereNull('deleted_at') ->first(); if (empty($playerBank)) { return jsonFailResponse(trans('player_bank_not_found', [], 'message')); } //计算汇率 $money = bcdiv($data['amount'], $currency->ratio, 2); //大于5000需要后台审核 /*if ($money >= 5000) { DB::beginTransaction(); try { $money = bcdiv($data['amount'], $currency->ratio, 2); // 生成订单 $playerWithdrawRecord = new PlayerWithdrawRecord(); $beforeGameAmount = $player->wallet->money; // 玩家钱包扣减 $player->wallet->money = bcsub($player->wallet->money, $data['amount'], 2); $playerWithdrawRecord->player_id = $player->id; $playerWithdrawRecord->department_id = $player->department_id; $playerWithdrawRecord->tradeno = createOrderNo(); $playerWithdrawRecord->player_name = $player->name ?? ''; $playerWithdrawRecord->player_phone = $player->phone ?? ''; $playerWithdrawRecord->money = $money; $playerWithdrawRecord->coins = $data['amount']; $playerWithdrawRecord->after_coins = $player->wallet->money; $playerWithdrawRecord->fee = 0; $playerWithdrawRecord->inmoney = bcsub($playerWithdrawRecord->money, $playerWithdrawRecord->fee, 2); // 实际提现金额 $playerWithdrawRecord->currency = $channel->currency; $playerWithdrawRecord->bank_name = $playerBank->bank_name; $playerWithdrawRecord->bank_code = $playerBank->bank_code; $playerWithdrawRecord->account = $playerBank->account; $playerWithdrawRecord->account_name = $playerBank->account_name; $playerWithdrawRecord->type = PlayerWithdrawRecord::TYPE_SELF; $playerWithdrawRecord->status = PlayerWithdrawRecord::STATUS_WAIT; $playerWithdrawRecord->save(); // 更新玩家统计 $player->player_extend->withdraw_amount = bcadd($player->player_extend->withdraw_amount, $playerWithdrawRecord->coins, 2); $player->push(); //寫入金流明細 $playerDeliveryRecord = new PlayerDeliveryRecord; $playerDeliveryRecord->player_id = $playerWithdrawRecord->player_id; $playerDeliveryRecord->department_id = $playerWithdrawRecord->department_id; $playerDeliveryRecord->target = $playerWithdrawRecord->getTable(); $playerDeliveryRecord->target_id = $playerWithdrawRecord->id; $playerDeliveryRecord->type = PlayerDeliveryRecord::TYPE_WITHDRAWAL; $playerDeliveryRecord->source = 'channel_withdrawal'; $playerDeliveryRecord->amount = $playerWithdrawRecord->coins; $playerDeliveryRecord->amount_before = $beforeGameAmount; $playerDeliveryRecord->amount_after = $player->wallet->money; $playerDeliveryRecord->tradeno = $playerWithdrawRecord->tradeno ?? ''; $playerDeliveryRecord->remark = $playerWithdrawRecord->remark ?? ''; $playerDeliveryRecord->save(); DB::commit(); } catch (\Exception $e) { DB::rollBack(); return jsonFailResponse(trans('system_error', [], 'message') . $e->getMessage()); } $notice = new Notice(); $notice->department_id = $playerWithdrawRecord->department_id; $notice->player_id = $playerWithdrawRecord->player_id; $notice->source_id = $playerWithdrawRecord->id; $notice->type = Notice::TYPE_EXAMINE_WITHDRAW; $notice->receiver = Notice::RECEIVER_DEPARTMENT; $notice->is_private = 0; $notice->title = '渠道提现待审核'; $notice->content = '提现订单待审核,玩家' . (empty($playerWithdrawRecord->player_name) ? $playerWithdrawRecord->player_name : $playerWithdrawRecord->player_phone) . ', 提现游戏点: ' . $playerWithdrawRecord->point . ' 提现金额: ' . $playerWithdrawRecord->money; $notice->save(); if ($playerWithdrawRecord->status == PlayerWithdrawRecord::STATUS_FAIL) { return jsonFailResponse(trans('withdraw_fail', [], 'message')); } sendSocketMessage('private-admin_group-channel-' . $channel->department_id, [ 'msg_type' => 'player_create_withdraw_order', 'id' => $playerWithdrawRecord->id, 'player_id' => $player->id, 'player_name' => $player->name, 'player_phone' => $player->phone, 'money' => $playerWithdrawRecord->money, 'status' => $playerWithdrawRecord->status, 'tradeno' => $playerWithdrawRecord->tradeno, ]); return jsonSuccessResponse('success', [ 'tradeno' => $playerWithdrawRecord->tradeno, 'order_id' => $playerWithdrawRecord->id, 'money' => $playerWithdrawRecord->money, 'currency' => $playerWithdrawRecord->currency, 'status' => $playerWithdrawRecord->status, ]); }*/ // 生成订单 $orderNo = createOrderNo(); $playerWithdrawRecord = new PlayerWithdrawRecord(); $beforeGameAmount = $player->wallet->money; // 玩家钱包扣减 $player->wallet->money = bcsub($player->wallet->money, $data['amount'], 2); $playerWithdrawRecord->player_id = $player->id; $playerWithdrawRecord->department_id = $player->department_id; $playerWithdrawRecord->tradeno = $orderNo; $playerWithdrawRecord->player_name = $player->name ?? ''; $playerWithdrawRecord->player_phone = $player->phone ?? ''; $playerWithdrawRecord->money = $money; $playerWithdrawRecord->coins = $data['amount']; $playerWithdrawRecord->after_coins = $player->wallet->money; $playerWithdrawRecord->fee = 0; $playerWithdrawRecord->inmoney = bcsub($playerWithdrawRecord->money, $playerWithdrawRecord->fee, 2); // 实际提现金额 $playerWithdrawRecord->currency = $channel->currency; DB::beginTransaction(); try { //银行卡提现 if ($data['type'] == 1) { $playerWithdrawRecord->bank_name = $playerBank->bank_name; $playerWithdrawRecord->bank_code = $playerBank->bank_code; $playerWithdrawRecord->account = $playerBank->account; $playerWithdrawRecord->account_name = $playerBank->account_name; $playerWithdrawRecord->type = PlayerWithdrawRecord::TYPE_SELF; $playerWithdrawRecord->status = PlayerWithdrawRecord::STATUS_WAIT; $playerWithdrawRecord->save(); //USDT提现 } elseif ($data['type'] == 2) { $rate = ChannelRechargeMethod::query() ->where('department_id', $player->department_id) ->where('type', 2) ->value('rate'); $playerWithdrawRecord->rate = $rate; $playerWithdrawRecord->currency = 'USDT'; $playerWithdrawRecord->wallet_address = $playerBank->wallet_address; $playerWithdrawRecord->qr_code = $playerBank->qr_code; $playerWithdrawRecord->type = PlayerWithdrawRecord::TYPE_USDT; $playerWithdrawRecord->status = PlayerWithdrawRecord::STATUS_WAIT; $playerWithdrawRecord->save(); //三方提现 } else { $params = [ 'amount' => $money, 'bankCode' => $playerBank->bank_code, 'bankAccountNo' => $playerBank->account, 'bankAccountName' => $playerBank->account_name, 'orderNo' => $orderNo, ]; $res = (new SklPayServices())->payout($params); if ($res['code'] == 'success') { $playerWithdrawRecord->bank_name = $playerBank->bank_name; $playerWithdrawRecord->bank_code = $playerBank->bank_code; $playerWithdrawRecord->account = $playerBank->account; $playerWithdrawRecord->account_name = $playerBank->account_name; $playerWithdrawRecord->talk_tradeno = $res['data']['reference_number']; $playerWithdrawRecord->type = PlayerWithdrawRecord::TYPE_SKLPAYOUT; $playerWithdrawRecord->status = PlayerWithdrawRecord::STATUS_WAIT; $playerWithdrawRecord->save(); } else { return jsonFailResponse($res['error']); } } DB::commit(); } catch (\Exception $e) { DB::rollBack(); return jsonFailResponse(trans('system_error', [], 'message') . $e->getMessage()); } // 更新玩家统计 $player->player_extend->withdraw_amount = bcadd($player->player_extend->withdraw_amount, $playerWithdrawRecord->coins, 2); $player->push(); //寫入金流明細 $playerDeliveryRecord = new PlayerDeliveryRecord; $playerDeliveryRecord->player_id = $playerWithdrawRecord->player_id; $playerDeliveryRecord->department_id = $playerWithdrawRecord->department_id; $playerDeliveryRecord->target = $playerWithdrawRecord->getTable(); $playerDeliveryRecord->target_id = $playerWithdrawRecord->id; $playerDeliveryRecord->type = PlayerDeliveryRecord::TYPE_WITHDRAWAL; $playerDeliveryRecord->source = 'channel_withdrawal'; $playerDeliveryRecord->amount = $playerWithdrawRecord->coins; $playerDeliveryRecord->amount_before = $beforeGameAmount; $playerDeliveryRecord->amount_after = $player->wallet->money; $playerDeliveryRecord->tradeno = $playerWithdrawRecord->tradeno ?? ''; $playerDeliveryRecord->remark = ''; $playerDeliveryRecord->save(); return jsonSuccessResponse('success', [ 'tradeno' => $playerWithdrawRecord->tradeno, 'money' => $playerWithdrawRecord->money, 'currency' => $playerWithdrawRecord->currency, 'status' => $playerWithdrawRecord->status, ]); } /** * 玩家账变记录 * @param Request $request * @return Response * @throws PlayerCheckException|PromoterCheckException */ public function playerDeliveryRecord(Request $request): Response { $player = checkPlayer(false); $validator = v::key('page', v::intVal()->setName(trans('page', [], 'message'))) ->key('type', v::stringVal()->setName(trans('date_type', [], 'message'))) ->key('size', v::intVal()->setName(trans('size', [], 'message'))); $data = $request->all(); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } try { $playerDeliveryRecordModel = PlayerDeliveryRecord::where('player_id', $player->id); switch ($data['type']) { case 'today': // 今天 $playerDeliveryRecordModel->whereDate('created_at', date('Y-m-d')); break; case 'week': // 本周 $playerDeliveryRecordModel->where('created_at', '>=', \Carbon\Carbon::today()->startOfWeek())->where('created_at', '<=', Carbon::today()->endOfWeek()); break; case 'month': // 本月 $playerDeliveryRecordModel->where('created_at', '>=', Carbon::today()->firstOfMonth())->where('created_at', '<=', Carbon::today()->endOfMonth()); break; case 'sub_month': // 上月 $playerDeliveryRecordModel->where('created_at', '>=', Carbon::today()->subMonth()->firstOfMonth())->where('created_at', '<=', Carbon::today()->subMonth()->endOfMonth()); break; default: $playerDeliveryRecordModel->whereDate('created_at', date('Y-m-d')); break; } $inType = implode(',', [ PlayerDeliveryRecord::TYPE_MODIFIED_AMOUNT_ADD, PlayerDeliveryRecord::TYPE_PRESENT_IN, PlayerDeliveryRecord::TYPE_GAME_IN, PlayerDeliveryRecord::TYPE_ACTIVITY_BONUS, PlayerDeliveryRecord::TYPE_REGISTER_PRESENT, PlayerDeliveryRecord::TYPE_PROFIT, PlayerDeliveryRecord::TYPE_LOTTERY, ]); $outType = implode(',', [ PlayerDeliveryRecord::TYPE_PRESENT_OUT, PlayerDeliveryRecord::TYPE_GAME_OUT, PlayerDeliveryRecord::TYPE_MODIFIED_AMOUNT_DEDUCT, ]); $totalModel = clone $playerDeliveryRecordModel; $totalData = $totalModel->selectRaw('sum(IF(type in (' . $inType . '), amount, 0)) as total_in, sum(IF(type in (' . $outType . '), amount, 0)) as total_out, sum(IF(type = ' . PlayerDeliveryRecord::TYPE_WITHDRAWAL . ', amount, 0)) as total_withdrawal, sum(IF(type = ' . PlayerDeliveryRecord::TYPE_WITHDRAWAL_BACK . ', amount, 0)) as total_withdrawal_back, sum(IF(type = ' . PlayerDeliveryRecord::TYPE_RECHARGE . ', amount, 0)) as total_recharge')->first(); $playerDeliveryRecord = $playerDeliveryRecordModel->forPage($data['page'], $data['size']) ->orderBy('id', 'desc') ->get(); $list = []; /** @var PlayerDeliveryRecord $item */ foreach ($playerDeliveryRecord as $item) { switch ($item->type) { case PlayerDeliveryRecord::TYPE_MODIFIED_AMOUNT_ADD: $item->target = trans('target.modified_amount_add', [], 'message'); break; case PlayerDeliveryRecord::TYPE_PRESENT_IN: $item->target = trans('target.present_in', [], 'message'); break; case PlayerDeliveryRecord::TYPE_PRESENT_OUT: $item->target = trans('target.present_out', [], 'message'); $item->amount = '-' . $item->amount; break; case PlayerDeliveryRecord::TYPE_GAME_OUT: $item->target = trans('target.machine_up', [], 'message'); $item->amount = '-' . $item->amount; break; case PlayerDeliveryRecord::TYPE_GAME_IN: $item->target = trans('target.machine_down', [], 'message'); break; case PlayerDeliveryRecord::TYPE_RECHARGE: switch ($item->source) { case 'artificial_recharge': $item->target = trans('target.artificial_recharge', [], 'message'); break; case 'self_recharge': $item->target = trans('target.self_recharge', [], 'message'); break; case 'talk_recharge': $item->target = trans('target.talk_recharge', [], 'message'); break; case 'coin_recharge': $item->target = trans('target.coin_recharge', [], 'message'); break; } break; case PlayerDeliveryRecord::TYPE_WITHDRAWAL: switch ($item['source']) { case 'artificial_withdrawal': $item->target = trans('target.artificial_withdrawal', [], 'message'); break; case 'talk_withdrawal': $item->target = trans('target.talk_withdrawal', [], 'message'); break; case 'channel_withdrawal': $item->target = trans('target.channel_withdrawal', [], 'message'); break; } $item->amount = '-' . $item->amount; break; case PlayerDeliveryRecord::TYPE_MODIFIED_AMOUNT_DEDUCT: $item->target = trans('target.modified_amount_deduct', [], 'message'); $item->amount = '-' . $item->amount; break; case PlayerDeliveryRecord::TYPE_WITHDRAWAL_BACK: $item->target = trans('target.withdrawal_back', [], 'message'); break; case PlayerDeliveryRecord::TYPE_ACTIVITY_BONUS: $item->target = trans('target.activity_bonus', [], 'message'); break; case PlayerDeliveryRecord::TYPE_REGISTER_PRESENT: $item->target = trans('target.register_present', [], 'message'); break; case PlayerDeliveryRecord::TYPE_PROFIT: $item->target = trans('target.profit', [], 'message'); break; default: break; } $list[] = [ 'id' => $item->id, 'amount' => $item->amount, 'source' => $item->target, 'amount_after' => $item->amount_after, 'created_at' => date('Y-m-d H:i:s', strtotime($item->created_at)), ]; } } catch (\Exception $e) { return jsonFailResponse($e->getMessage()); } return jsonSuccessResponse('success', [ 'list' => $list, 'player' => [ 'uuid' => $player->uuid, 'name' => $player->name, 'promoter_uuid' => $player->uuid, ], 'total_data' => [ 'total_in' => $totalData['total_in'] ?? 0, 'total_out' => $totalData['total_out'] ?? 0, 'total_withdrawal' => bcsub($totalData['total_withdrawal'] ?? 0, $totalData['total_withdrawal_back'] ?? 0, 2), 'total_recharge' => $totalData['total_recharge'] ?? 0, ], 'date_type' => [ 'today' => Carbon::today()->format('Y-m-d'), 'week' => Carbon::today()->startOfWeek()->format('Y-m-d') . '~' . Carbon::today()->endOfWeek()->format('Y-m-d'), 'month' => Carbon::today()->firstOfMonth()->format('Y-m-d') . '~' . Carbon::today()->endOfMonth()->format('Y-m-d'), 'sub_month' => Carbon::today()->subMonth()->firstOfMonth()->format('Y-m-d') . '~' . Carbon::today()->subMonth()->endOfMonth()->format('Y-m-d'), ] ]); } /** * 游戏记录 * @param Request $request * @return Response * @throws PlayerCheckException|GameException */ public function gameRecord(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('page', v::intVal()->setName(trans('page', [], 'message'))) ->key('size', v::intVal()->setName(trans('size', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } $records = DrawRecord::query() ->select('prize_pic', 'prize_name', 'prize_type', 'draw_time', 'ip') ->where('uid', $player->id) ->orderBy('id', 'desc') ->forPage($data['page'], $data['size']) ->get() ->toArray(); return jsonSuccessResponse('success', $records); } /** * 充提记录 * @param Request $request * @return Response * @throws PlayerCheckException|GameException */ public function depositWithdrawalRecord(Request $request): Response { $player = checkPlayer(); $data = $request->all(); $validator = v::key('page', v::intVal()->setName(trans('page', [], 'message'))) ->key('size', v::intVal()->setName(trans('size', [], 'message'))) ->key('type', v::intVal()->setName(trans('type', [], 'message'))) ->key('start_date', v::stringVal()->setName(trans('start_date', [], 'message'))) ->key('end_date', v::stringVal()->setName(trans('end_date', [], 'message'))); try { $validator->assert($data); } catch (AllOfException $e) { return jsonFailResponse(getValidationMessages($e)); } // 1. 构建充值查询 $rechargeQuery = DB::table('player_recharge_record') ->select('money', 'created_at', 'status', DB::raw("1 as type")) ->where('player_id', $player->id) ->whereBetween('created_at', [$data['start_date'],date('Y-m-d', strtotime("{$data['end_date']} +1 days"))]); // 2. 构建提现查询 $withdrawQuery = DB::table('player_withdraw_record') ->select('money', 'created_at', 'status', DB::raw("2 as type")) ->where('player_id', $player->id) ->whereBetween('created_at', [$data['start_date'],date('Y-m-d', strtotime("{$data['end_date']} +1 days"))]); // 3. 根据类型参数过滤 if ($data['type'] == 1) { $query = $rechargeQuery; } elseif ($data['type'] == 2) { $query = $withdrawQuery; } else { $query = $rechargeQuery->unionAll($withdrawQuery); } // 4. 处理排序和分页 $records = DB::table(DB::raw("({$query->toSql()}) as combined_transactions")) ->mergeBindings($query) // 重要:合并 SQL 绑定参数 ->orderBy('created_at', 'desc') ->forPage($data['page'], $data['size']) ->get()->toArray(); return jsonSuccessResponse('success', $records); } }