Files
webman-buildadmin/app/admin/controller/game/PlayRecord.php
zhenhui e65c3474bd 1.修改电话号码格式为60前缀,马来西亚格式
2.优化渠道可以查看分红方式,可以查看游玩详情
2026-05-30 11:09:54 +08:00

314 lines
12 KiB
PHP
Raw Permalink 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\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->shouldApplyUserAdminScope()) {
$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->shouldApplyUserAdminScope()) {
$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->shouldApplyUserAdminScope()) {
$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;
}
}