diff --git a/app/api/controller/v1/Playx.php b/app/api/controller/v1/Playx.php index f181db5..c207e5d 100644 --- a/app/api/controller/v1/Playx.php +++ b/app/api/controller/v1/Playx.php @@ -173,16 +173,6 @@ class Playx extends Api } } - $requestId = $body['request_id'] ?? ''; - $date = $body['date'] ?? ''; - $playxUserId = strval($body['user_id'] ?? ''); - $yesterdayWinLossNet = $body['yesterday_win_loss_net'] ?? 0; - $yesterdayTotalDeposit = $body['yesterday_total_deposit'] ?? 0; - - if ($requestId === '' || $date === '' || $playxUserId === '') { - return $this->error(__('Missing required fields: request_id, date, user_id')); - } - $secret = config('playx.daily_push_secret', ''); if ($secret !== '') { $sig = $request->header('X-Signature', ''); @@ -198,6 +188,130 @@ class Playx extends Api } } + // ===== 新版批量上报格式 ===== + // 兼容你们截图:{ report_date, member:[{member_id, login, lty_deposit, lty_withdrawal, yesterday_total_w, yesterday_total_deposit}, ...] } + if (isset($body['report_date']) && isset($body['member']) && is_array($body['member'])) { + $reportDate = $body['report_date']; + $date = ''; + if (is_numeric($reportDate)) { + $date = date('Y-m-d', intval($reportDate)); + } else { + $date = strval($reportDate); + } + + $members = $body['member']; + if ($date === '' || empty($members)) { + return $this->error(__('Missing required fields: report_date, member')); + } + + $requestId = strval($body['request_id'] ?? ''); + if ($requestId === '') { + $requestId = 'report_' . $date; + } + + $returnRatio = config('playx.return_ratio', 0.1); + $unlockRatio = config('playx.unlock_ratio', 0.1); + + $results = []; + $allDeduped = true; + + foreach ($members as $m) { + $playxUserId = strval($m['member_id'] ?? ''); + if ($playxUserId === '') { + return $this->error(__('Missing required fields: member_id')); + } + + $username = strval($m['login'] ?? ''); + $yesterdayWinLossNet = $m['yesterday_total_w'] ?? 0; + $yesterdayTotalDeposit = $m['yesterday_total_deposit'] ?? 0; + $lifetimeTotalDeposit = $m['lty_deposit'] ?? 0; + $lifetimeTotalWithdraw = $m['lty_withdrawal'] ?? 0; + + $exists = MallPlayxDailyPush::where('user_id', $playxUserId)->where('date', $date)->find(); + if ($exists) { + $results[] = [ + 'user_id' => $playxUserId, + 'deduped' => true, + 'accepted' => true, + 'message' => __('Duplicate input'), + ]; + continue; + } + + Db::startTrans(); + try { + MallPlayxDailyPush::create([ + 'user_id' => $playxUserId, + 'date' => $date, + 'username' => $username, + 'yesterday_win_loss_net' => $yesterdayWinLossNet, + 'yesterday_total_deposit' => $yesterdayTotalDeposit, + 'lifetime_total_deposit' => $lifetimeTotalDeposit, + 'lifetime_total_withdraw' => $lifetimeTotalWithdraw, + 'create_time' => time(), + ]); + + $newLocked = 0; + if ($yesterdayWinLossNet < 0) { + $newLocked = intval(round(abs(floatval($yesterdayWinLossNet)) * $returnRatio)); + } + $todayLimit = intval(round(floatval($yesterdayTotalDeposit) * $unlockRatio)); + + $asset = $this->ensureAssetForPlayx($playxUserId, $username); + if (!$asset) { + throw new \RuntimeException(__('Failed to map playx user to mall user')); + } + + if ($asset->today_limit_date !== $date) { + $asset->today_claimed = 0; + $asset->today_limit_date = $date; + } + + $asset->locked_points = intval($asset->locked_points ?? 0) + $newLocked; + $asset->today_limit = $todayLimit; + $asset->playx_user_id = $playxUserId; + + $uname = trim($username); + if ($uname !== '') { + $asset->username = $uname; + } + $asset->save(); + + Db::commit(); + + $results[] = [ + 'user_id' => $playxUserId, + 'deduped' => false, + 'accepted' => true, + 'message' => __('Ok'), + ]; + $allDeduped = false; + } catch (\Throwable $e) { + Db::rollback(); + return $this->error($e->getMessage()); + } + } + + return $this->success('', [ + 'request_id' => $requestId, + 'accepted' => true, + 'deduped' => $allDeduped, + 'message' => $allDeduped ? __('Duplicate input') : __('Ok'), + 'results' => $results, + ]); + } + + // ===== 旧版单条上报格式(兼容)===== + $requestId = $body['request_id'] ?? ''; + $date = $body['date'] ?? ''; + $playxUserId = strval($body['user_id'] ?? ''); + $yesterdayWinLossNet = $body['yesterday_win_loss_net'] ?? 0; + $yesterdayTotalDeposit = $body['yesterday_total_deposit'] ?? 0; + + if ($requestId === '' || $date === '' || $playxUserId === '') { + return $this->error(__('Missing required fields: request_id, date, user_id')); + } + $exists = MallPlayxDailyPush::where('user_id', $playxUserId)->where('date', $date)->find(); if ($exists) { return $this->success('', [ @@ -221,10 +335,9 @@ class Playx extends Api 'create_time' => time(), ]); + $newLocked = 0; $returnRatio = config('playx.return_ratio', 0.1); $unlockRatio = config('playx.unlock_ratio', 0.1); - - $newLocked = 0; if ($yesterdayWinLossNet < 0) { $newLocked = intval(round(abs(floatval($yesterdayWinLossNet)) * $returnRatio)); } @@ -234,14 +347,16 @@ class Playx extends Api if (!$asset) { throw new \RuntimeException(__('Failed to map playx user to mall user')); } - $todayLimitDate = $date; - if ($asset->today_limit_date !== $todayLimitDate) { + + if ($asset->today_limit_date !== $date) { $asset->today_claimed = 0; - $asset->today_limit_date = $todayLimitDate; + $asset->today_limit_date = $date; } + $asset->locked_points = intval($asset->locked_points ?? 0) + $newLocked; $asset->today_limit = $todayLimit; $asset->playx_user_id = $playxUserId; + $uname = trim(strval($body['username'] ?? '')); if ($uname !== '') { $asset->username = $uname; diff --git a/docs/PlayX-接口文档.md b/docs/PlayX-接口文档.md index b6009c0..ef0f74d 100644 --- a/docs/PlayX-接口文档.md +++ b/docs/PlayX-接口文档.md @@ -38,6 +38,36 @@ | `lifetime_total_deposit` | number | 否 | 历史总充值 | | `lifetime_total_withdraw` | number | 否 | 历史总提现 | +##### 格式 B:新版批量上报(兼容你截图) +新版 body 形如: +```json +{ + "report_date": "1700000000", + "member": [ + { + "member_id": "123456", + "login": "john", + "lty_deposit": 15230.75, + "lty_withdrawal": 12400.50, + "yesterday_total_w": -320.25, + "yesterday_total_deposit": 500.00 + } + ] +} +``` + +字段映射(服务端内部会转换成旧字段再计算): +- `report_date` -> `date`(若为 Unix 秒则转为 `YYYY-MM-DD`) +- `member[].member_id` -> `user_id` +- `member[].login` -> `username` +- `member[].yesterday_total_w` -> `yesterday_win_loss_net` +- `member[].yesterday_total_deposit` -> `yesterday_total_deposit` +- `member[].lty_deposit` -> `lifetime_total_deposit` +- `member[].lty_withdrawal` -> `lifetime_total_withdraw` + +返回补充: +- 批量模式会在 `data` 里增加 `results[]`,每个成员一条结果(是否 `deduped`)。 + #### 幂等规则 * 幂等键:`user_id + date` * 重复推送:不会重复入账,返回 `data.deduped=true` @@ -97,6 +127,49 @@ curl -X POST 'http://localhost:1818/api/v1/playx/daily-push' \ } ``` +#### 示例(新版批量上报) +请求: +```bash +curl -X POST 'http://localhost:1818/api/v1/playx/daily-push' \ + -H 'Content-Type: application/json' \ + -d '{ + "report_date": "1700000000", + "member": [ + { + "member_id": "123456", + "login": "john", + "lty_deposit": 15230.75, + "lty_withdrawal": 12400.50, + "yesterday_total_w": -320.25, + "yesterday_total_deposit": 500.00 + } + ] + }' +``` + +返回(首次写入至少一个成员时的示例): +```json +{ + "code": 1, + "msg": "", + "time": 0, + "data": { + "request_id": "report_2023-11-14", + "accepted": true, + "deduped": false, + "message": "Ok", + "results": [ + { + "user_id": "123456", + "accepted": true, + "deduped": false, + "message": "Ok" + } + ] + } +} +``` + --- ## 2. PlayX -> 积分商城(商城调用 PlayX)