314 lines
12 KiB
PHP
314 lines
12 KiB
PHP
<?php
|
||
|
||
namespace app\admin\controller\game;
|
||
|
||
use app\common\controller\Backend;
|
||
use app\common\service\GameBetSettleService;
|
||
use support\think\Db;
|
||
use support\Response;
|
||
use Webman\Http\Request as WebmanRequest;
|
||
|
||
/**
|
||
* 游玩记录(原压注订单)
|
||
*/
|
||
class PlayRecord extends Backend
|
||
{
|
||
protected ?object $model = null;
|
||
|
||
protected bool $modelValidate = false;
|
||
|
||
protected string|array $quickSearchField = ['id', 'period_no', 'idempotency_key'];
|
||
|
||
protected string|array $defaultSortField = ['id' => 'desc'];
|
||
|
||
protected string|array $orderGuarantee = ['id' => 'desc'];
|
||
|
||
protected array $withJoinTable = ['user', 'channel', 'gameRecord'];
|
||
|
||
protected function initController(WebmanRequest $request): ?Response
|
||
{
|
||
$this->model = new \app\common\model\PlayRecord();
|
||
return null;
|
||
}
|
||
|
||
public function add(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
return $this->error(__('Play record is generated by game API; manual creation is not allowed'));
|
||
}
|
||
|
||
public function edit(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
return $this->error(__('Play record cannot be edited'));
|
||
}
|
||
|
||
public function del(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
return $this->error(__('Play record cannot be deleted'));
|
||
}
|
||
|
||
public function sortable(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
return $this->error(__('Sorting is not supported'));
|
||
}
|
||
|
||
protected function _index(): Response
|
||
{
|
||
if ($this->request && $this->request->get('select')) {
|
||
return $this->select($this->request);
|
||
}
|
||
|
||
list($where, $alias, $limit, $order) = $this->queryBuilder();
|
||
$table = strtolower($this->model->getTable());
|
||
$mainShort = $alias[$table] ?? '';
|
||
if ($mainShort !== '' && $this->auth && !$this->auth->isSuperAdmin()) {
|
||
$where[] = ['user.admin_id', 'in', $this->scopedAdminIds()];
|
||
}
|
||
|
||
// 避免 ThinkORM withJoin 对 game_record 的字段缓存导致 select 出已删除列(如 preset_number)
|
||
// 这里改为手写 join + 明确 field 列表,保证数据库字段变更后不受 schema 缓存影响。
|
||
$query = Db::name($table)->alias($mainShort !== '' ? $mainShort : 'play_record')
|
||
->leftJoin('user user', 'user.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.user_id')
|
||
->leftJoin('channel channel', 'channel.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.channel_id')
|
||
->leftJoin('game_record game_record', 'game_record.id = ' . ($mainShort !== '' ? $mainShort : 'play_record') . '.period_id')
|
||
->where($where);
|
||
|
||
$res = $query
|
||
->field([
|
||
($mainShort !== '' ? $mainShort : 'play_record') . '.*',
|
||
'user.username as user__username',
|
||
'user.phone as user__phone',
|
||
'channel.name as channel__name',
|
||
'game_record.period_no as gameRecord__period_no',
|
||
'game_record.status as gameRecord__status',
|
||
'game_record.result_number as gameRecord__result_number',
|
||
])
|
||
->order($order)
|
||
->paginate($limit);
|
||
|
||
$list = $res->items();
|
||
$total = $res->total();
|
||
|
||
// 将 join 扁平字段还原为原页面所需结构:user/channel/gameRecord
|
||
foreach ($list as $idx => $row) {
|
||
if (!is_array($row)) {
|
||
continue;
|
||
}
|
||
$row['user'] = [
|
||
'username' => isset($row['user__username']) ? (string) $row['user__username'] : '',
|
||
'phone' => isset($row['user__phone']) ? (string) $row['user__phone'] : '',
|
||
];
|
||
$row['channel'] = [
|
||
'name' => isset($row['channel__name']) ? (string) $row['channel__name'] : '',
|
||
];
|
||
$row['gameRecord'] = [
|
||
'period_no' => isset($row['gameRecord__period_no']) ? (string) $row['gameRecord__period_no'] : '',
|
||
'status' => isset($row['gameRecord__status']) && is_numeric((string) $row['gameRecord__status'])
|
||
? (int) $row['gameRecord__status']
|
||
: null,
|
||
'result_number' => isset($row['gameRecord__result_number']) && $row['gameRecord__result_number'] !== '' && $row['gameRecord__result_number'] !== null
|
||
? (string) $row['gameRecord__result_number']
|
||
: null,
|
||
];
|
||
unset(
|
||
$row['user__username'],
|
||
$row['user__phone'],
|
||
$row['channel__name'],
|
||
$row['gameRecord__period_no'],
|
||
$row['gameRecord__status'],
|
||
$row['gameRecord__result_number'],
|
||
);
|
||
$list[$idx] = $row;
|
||
}
|
||
|
||
$threshold = $this->jackpotMaxAmount();
|
||
foreach ($list as $idx => $row) {
|
||
if (!is_array($row)) {
|
||
continue;
|
||
}
|
||
$status = isset($row['status']) && is_numeric($row['status']) ? (int) $row['status'] : 0;
|
||
$win = bcadd(strval($row['win_amount'] ?? '0'), '0', 2);
|
||
$needReview = bccomp($threshold, '0', 2) > 0 && bccomp($win, $threshold, 2) >= 0;
|
||
$canApprove = $needReview && $status === GameBetSettleService::PLAY_STATUS_PENDING_REVIEW;
|
||
$row['jackpot_need_review'] = $needReview ? 1 : 0;
|
||
$row['can_jackpot_approve'] = $canApprove ? 1 : 0;
|
||
$list[$idx] = $row;
|
||
}
|
||
|
||
return $this->success('', [
|
||
'list' => $list,
|
||
'total' => $total,
|
||
'remark' => get_route_remark(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 大奖审核通过并派彩(仅 win_amount >= game_config.jackpot_max_amount 且 status=待审核 才可操作)
|
||
*/
|
||
public function approveJackpot(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
if ($request->method() !== 'POST') {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
|
||
$idRaw = $request->post('id');
|
||
if ($idRaw === null || $idRaw === '' || !is_numeric(strval($idRaw))) {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
$id = (int) $idRaw;
|
||
if ($id <= 0) {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
$remarkRaw = $request->post('remark');
|
||
$remark = is_string($remarkRaw) ? trim($remarkRaw) : '';
|
||
|
||
// 权限范围校验:复用列表逻辑(非超管只能操作其下辖用户)
|
||
if ($this->auth && !$this->auth->isSuperAdmin()) {
|
||
$uidRaw = Db::name('game_play_record')->where('id', $id)->value('user_id');
|
||
$uid = ($uidRaw === null || $uidRaw === '' || !is_numeric(strval($uidRaw))) ? 0 : (int) $uidRaw;
|
||
if ($uid <= 0) {
|
||
return $this->error(__('Record not found'));
|
||
}
|
||
$ownerAdminId = Db::name('user')->where('id', $uid)->value('admin_id');
|
||
$aid = ($ownerAdminId === null || $ownerAdminId === '' || !is_numeric(strval($ownerAdminId))) ? 0 : (int) $ownerAdminId;
|
||
if ($aid <= 0 || !in_array($aid, $this->scopedAdminIds(), true)) {
|
||
return $this->error(__('You have no permission'));
|
||
}
|
||
}
|
||
|
||
$adminId = $this->auth ? (int) ($this->auth->id ?? 0) : 0;
|
||
|
||
Db::startTrans();
|
||
try {
|
||
$result = GameBetSettleService::approveJackpotPlayRecord($id, $adminId, $remark);
|
||
if (($result['ok'] ?? false) !== true) {
|
||
Db::rollback();
|
||
$msg = is_string($result['msg'] ?? null) ? $result['msg'] : __('Parameter error');
|
||
return $this->error($msg);
|
||
}
|
||
Db::commit();
|
||
} catch (\Throwable $e) {
|
||
Db::rollback();
|
||
return $this->error($e->getMessage());
|
||
}
|
||
|
||
return $this->success(__('Approved'));
|
||
}
|
||
|
||
/**
|
||
* 大奖审核拒绝(remark 必填)
|
||
*/
|
||
public function rejectJackpot(WebmanRequest $request): Response
|
||
{
|
||
$response = $this->initializeBackend($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
if ($request->method() !== 'POST') {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
$idRaw = $request->post('id');
|
||
if ($idRaw === null || $idRaw === '' || !is_numeric(strval($idRaw))) {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
$id = (int) $idRaw;
|
||
if ($id <= 0) {
|
||
return $this->error(__('Parameter error'));
|
||
}
|
||
$remarkRaw = $request->post('remark');
|
||
$remark = is_string($remarkRaw) ? trim($remarkRaw) : '';
|
||
if ($remark === '') {
|
||
return $this->error(__('Please provide reject reason'));
|
||
}
|
||
|
||
if ($this->auth && !$this->auth->isSuperAdmin()) {
|
||
$uidRaw = Db::name('game_play_record')->where('id', $id)->value('user_id');
|
||
$uid = ($uidRaw === null || $uidRaw === '' || !is_numeric(strval($uidRaw))) ? 0 : (int) $uidRaw;
|
||
if ($uid <= 0) {
|
||
return $this->error(__('Record not found'));
|
||
}
|
||
$ownerAdminId = Db::name('user')->where('id', $uid)->value('admin_id');
|
||
$aid = ($ownerAdminId === null || $ownerAdminId === '' || !is_numeric(strval($ownerAdminId))) ? 0 : (int) $ownerAdminId;
|
||
if ($aid <= 0 || !in_array($aid, $this->scopedAdminIds(), true)) {
|
||
return $this->error(__('You have no permission'));
|
||
}
|
||
}
|
||
|
||
$adminId = $this->auth ? (int) ($this->auth->id ?? 0) : 0;
|
||
Db::startTrans();
|
||
try {
|
||
$result = GameBetSettleService::rejectJackpotPlayRecord($id, $adminId, $remark);
|
||
if (($result['ok'] ?? false) !== true) {
|
||
Db::rollback();
|
||
$msg = is_string($result['msg'] ?? null) ? $result['msg'] : __('Parameter error');
|
||
return $this->error($msg);
|
||
}
|
||
Db::commit();
|
||
} catch (\Throwable $e) {
|
||
Db::rollback();
|
||
return $this->error($e->getMessage());
|
||
}
|
||
return $this->success(__('Rejected'));
|
||
}
|
||
|
||
/**
|
||
* @return int[]
|
||
*/
|
||
private function scopedAdminIds(): array
|
||
{
|
||
if (!$this->auth) {
|
||
return [0];
|
||
}
|
||
if ($this->auth->isSuperAdmin()) {
|
||
return [];
|
||
}
|
||
$groupIds = $this->auth->getAdminChildGroups();
|
||
$adminIds = $groupIds ? $this->auth->getGroupAdmins($groupIds) : [];
|
||
$adminIds[] = $this->auth->id;
|
||
$adminIds = array_map(static fn($id) => intval(strval($id)), $adminIds);
|
||
$adminIds = array_values(array_unique(array_filter($adminIds, static fn($id) => $id > 0)));
|
||
return $adminIds === [] ? [0] : $adminIds;
|
||
}
|
||
|
||
private function jackpotMaxAmount(): string
|
||
{
|
||
$row = Db::name('game_config')->where('config_key', GameBetSettleService::CONFIG_KEY_JACKPOT_MAX_AMOUNT)->find();
|
||
if (!is_array($row)) {
|
||
return '0.00';
|
||
}
|
||
$raw = $row['config_value'] ?? null;
|
||
if ($raw === null || $raw === '') {
|
||
return '0.00';
|
||
}
|
||
$v = is_string($raw) ? trim($raw) : (is_numeric($raw) ? strval($raw) : '');
|
||
if ($v === '' || !is_numeric($v)) {
|
||
return '0.00';
|
||
}
|
||
$normalized = bcadd($v, '0', 2);
|
||
if (bccomp($normalized, '0', 2) <= 0) {
|
||
return '0.00';
|
||
}
|
||
return $normalized;
|
||
}
|
||
}
|
||
|