Files
cursor/plans/注册奖励随机游戏_9f41e4af.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

161 lines
6.2 KiB
Markdown
Raw 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.

---
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` 预展示候选游戏(非领取必需)