初始化

This commit is contained in:
2026-03-02 13:44:38 +08:00
commit 05b785083c
677 changed files with 58662 additions and 0 deletions

View File

@@ -0,0 +1,1251 @@
<?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);
}
}