Files
dafuweng/app/api/controller/v1/PlayerController.php
2026-03-02 13:44:38 +08:00

1252 lines
56 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller\v1;
use addons\webman\model\BankList;
use addons\webman\model\Channel;
use addons\webman\model\ChannelRechargeMethod;
use addons\webman\model\ChannelRechargeSetting;
use addons\webman\model\Currency;
use addons\webman\model\DrawRecord;
use addons\webman\model\Game;
use addons\webman\model\PlayerRechargeRecord;
use addons\webman\model\Notice;
use addons\webman\model\Player;
use addons\webman\model\PlayerBank;
use addons\webman\model\PlayerDeliveryRecord;
use addons\webman\model\PlayerWithdrawRecord;
use addons\webman\model\Prize;
use addons\webman\model\SepayRecharge;
use app\exception\PromoterCheckException;
use app\exception\GameException;
use app\exception\PlayerCheckException;
use app\service\SklPayServices;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Validator as v;
use support\Db;
use support\Request;
use support\Response;
use think\Exception;
use Tinywan\Jwt\JwtToken;
use addons\webman\model\PhoneSmsLog;
use support\Redis;
use Webman\Push\PushException;
class PlayerController
{
/** 排除验签 */
protected $noNeedSign = [];
/**
* 登录接口
* @param Request $request
* @return Response
* @throws \Exception
*/
public function login(Request $request): Response
{
$validator = v::key('phone', v::stringType()->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);
}
}