This commit is contained in:
ray zhou
2026-05-29 11:21:40 +08:00
parent 5d6d482efe
commit f71a5c59af
447 changed files with 32245 additions and 116 deletions

View File

@@ -0,0 +1,160 @@
---
name: 注册奖励随机游戏
overview: 在 slot_console 注册活动type=7领取成功响应中从活动 ext_config.game_ids 配置的候选池里,按当前渠道 game_model_id 过滤已上架游戏后随机返回 game_id供前端直接进游戏。
todos:
- id: model-published-ids
content: GameApiModel 新增 publishedGameIds(gameModelId, gameIds) 查询
status: completed
- id: logic-pick-random
content: 新增 RegisterRewardLogic::pickRandomGameId 解析 ext_config 并随机
status: completed
- id: entity-receive
content: ActivityConfigEntity ACTIVITY_TYPE_REG 成功分支接入 Logic 并扩展返回
status: completed
- id: controller-phpdoc
content: GiftController::receive PHPDoc 补充 game_id 字段说明
status: completed
- id: unit-tests
content: RegisterRewardLogicTest + php82 容器跑单测
status: completed
isProject: false
---
# 注册奖励领取后随机返回 game_id
## 背景与范围
- **入口**[`POST /api/gift/receive`](slot_console/app/api/controller/GiftController.php) → [`ActivityConfigEntity::receive()`](slot_console/app/entity/activity/ActivityConfigEntity.php) 中 `ACTIVITY_TYPE_REG`type=7
- **不在范围**:注册自动到账(`UserRegisterEventService`)、后台 Vue 配置页、前端进游戏逻辑。
- **配置来源**(已确认):活动表 `s_recharge_gift_config.ext_config.game_ids`
当前领取成功仅返回金额:
```750:750:slot_console/app/entity/activity/ActivityConfigEntity.php
return ['gift_coin' => CommonFn::getNumberFormat($giftAmount), 'gift_bonus' => CommonFn::getNumberFormat($giftBonus)];
```
`game_id` 语义与大厅一致:[`s_game_api.game_id`](slot_console/app/model/GameApiModel.php) = `game.id`,前端用该 ID 调 `POST /api/game/login` 的 `gameId` 或 napi 搜索同款字段。
## 配置契约
在对应注册活动type=7的 `ext_config` 中增加:
```json
{
"game_ids": [101, 205, 308]
}
```
- `game_ids``int[]`,运营在 DB/后台 JSON 中维护;本任务不实现 admin UI。
- 未配置、空数组、或过滤后无有效游戏:**不阻断领取**,响应中 **省略 `game_id` 字段**(与 `withdraw_guide` 用 `0` 不同,避免前端误开游戏)。
## 数据流
```mermaid
sequenceDiagram
Client->>GiftController: POST /api/gift/receive id=activityId
GiftController->>ActivityConfigEntity: receive()
ActivityConfigEntity->>WalletService: gift() 注册赠送入账
ActivityConfigEntity->>RegisterRewardLogic: pickRandomGameId(ext_config, gameModelId)
RegisterRewardLogic->>GameApiModel: 过滤 status=1 且已发布
RegisterRewardLogic-->>ActivityConfigEntity: game_id|null
ActivityConfigEntity-->>Client: gift_coin, gift_bonus, game_id?
```
## 实现要点
### 1. 新增 Logic随机选游戏
新建 [`slot_console/app/api/logic/RegisterRewardLogic.php`](slot_console/app/api/logic/RegisterRewardLogic.php)(参考 [`FreeCreditsLogic`](slot_console/app/api/logic/FreeCreditsLogic.php) 的独立 Logic 拆分方式):
| 方法 | 职责 |
| --- | --- |
| `pickRandomGameId(array\|null $extConfig, int $gameModelId): ?int` | 解析 `game_ids` → 去重/转 int → 调 Model 过滤 → `array_rand` 返回一个 id |
解析规则:
- 支持 `game_ids` 为 JSON 数组或逗号分隔字符串(防御性,与部分旧配置风格兼容)。
- 非法/非正整数丢弃。
### 2. Model候选池与渠道上架交集
在 [`GameApiModel`](slot_console/app/model/GameApiModel.php) 增加查询方法,例如:
```php
public static function publishedGameIds(int $gameModelId, array $gameIds): array
```
条件:`game_id IN (...)`、`game_model_id = $gameModelId`、`status = STATUS_ON`;返回可用 `game_id` 列表。
不在 Logic 里直接拼 SQL符合分层规则。
### 3. 改动领取分支
在 [`ActivityConfigEntity::receive()`](slot_console/app/entity/activity/ActivityConfigEntity.php) 的 `ACTIVITY_TYPE_REG` case
- 发奖逻辑保持不变(`WalletService::gift` + `sendRegisterGiftWagerTask` + `setActivityFinishById`)。
- **仅在 `$res` 非空(领取成功)后**
- 用 `$this->where('id', $activityId)->find()` 读取原始 `ext_config``getActivityByInfo()` 经 `getGiftItemsByActivity` 组装,**不含** ext_config与兑换码分支读库方式一致
- `$gameModelId = $this->_modelId`(已由 `setSource` 设置)。
- 调用 `RegisterRewardLogic::pickRandomGameId()`。
- 在方法末尾统一组装返回:有值则追加 `'game_id' => $pickedId`。
[`GiftController::receive()`](slot_console/app/api/controller/GiftController.php) 补充 PHPDoc`data.game_id`int可选领取注册活动成功且配置了有效候选池时返回
### 4. 响应示例
成功且命中游戏:
```json
{
"code": 0,
"data": {
"gift_coin": "10.00",
"gift_bonus": "0.00",
"game_id": 205
}
}
```
成功但无可用游戏:仅 `gift_coin` / `gift_bonus`(与现网兼容)。
## 单测
新建 [`slot_console/tests/Unit/RegisterRewardLogicTest.php`](slot_console/tests/Unit/RegisterRewardLogicTest.php)
- `game_ids` 为空 / 缺失 → `null`
- 字符串 `"1,2,3"` 解析
- Model 层可用 stub 或 sqlite/内存 mock若项目已有 GameApi 测试惯例则对齐)
在 docker 内执行:
```bash
docker exec -w /app/www/slot/slot_console php82 ./vendor/bin/phpunit tests/Unit/RegisterRewardLogicTest.php
```
## 运维配置说明(无 UI
对目标渠道 type=7 活动,更新 `s_recharge_gift_config.ext_config`
```sql
-- 示例:在现有 ext_config 上合并 game_ids
UPDATE s_recharge_gift_config
SET ext_config = JSON_SET(COALESCE(ext_config, '{}'), '$.game_ids', JSON_ARRAY(101, 205))
WHERE id = <activity_id> AND type = 7;
```
`game_ids` 须为当前 `model_id` 下已在 `s_game_api` 上架的 `game.id`。
## 风险与边界
| 场景 | 行为 |
| --- | --- |
| 配置了已下架/未发布游戏 | 从池中剔除;池空则不下发 `game_id` |
| 重复领取 | 现有 `Is Got` 拦截,不会二次随机 |
| 多注册活动同渠道 | 按请求的 `id` 读对应活动 `ext_config` |
## 后续可选(本任务不做)
- slot_admin 活动编辑页 type=7 增加「推荐游戏」多选,写入 `ext_config.game_ids`
- `getActivityList` 预展示候选游戏(非领取必需)