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

6.2 KiB
Raw Blame History

name, overview, todos, isProject
name overview todos isProject
注册奖励随机游戏 在 slot_console 注册活动type=7领取成功响应中从活动 ext_config.game_ids 配置的候选池里,按当前渠道 game_model_id 过滤已上架游戏后随机返回 game_id供前端直接进游戏。
id content status
model-published-ids GameApiModel 新增 publishedGameIds(gameModelId, gameIds) 查询 completed
id content status
logic-pick-random 新增 RegisterRewardLogic::pickRandomGameId 解析 ext_config 并随机 completed
id content status
entity-receive ActivityConfigEntity ACTIVITY_TYPE_REG 成功分支接入 Logic 并扩展返回 completed
id content status
controller-phpdoc GiftController::receive PHPDoc 补充 game_id 字段说明 completed
id content status
unit-tests RegisterRewardLogicTest + php82 容器跑单测 completed
false

注册奖励领取后随机返回 game_id

背景与范围

  • 入口POST /api/gift/receiveActivityConfigEntity::receive()ACTIVITY_TYPE_REGtype=7
  • 不在范围:注册自动到账(UserRegisterEventService)、后台 Vue 配置页、前端进游戏逻辑。
  • 配置来源(已确认):活动表 s_recharge_gift_config.ext_config.game_ids

当前领取成功仅返回金额:

        return ['gift_coin' => CommonFn::getNumberFormat($giftAmount), 'gift_bonus' => CommonFn::getNumberFormat($giftBonus)];

game_id 语义与大厅一致:s_game_api.game_id = game.id,前端用该 ID 调 POST /api/game/logingameId 或 napi 搜索同款字段。

配置契约

在对应注册活动type=7ext_config 中增加:

{
  "game_ids": [101, 205, 308]
}
  • game_idsint[],运营在 DB/后台 JSON 中维护;本任务不实现 admin UI。
  • 未配置、空数组、或过滤后无有效游戏:不阻断领取,响应中 省略 game_id 字段(与 withdraw_guide0 不同,避免前端误开游戏)。

数据流

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(参考 FreeCreditsLogic 的独立 Logic 拆分方式):

方法 职责
pickRandomGameId(array|null $extConfig, int $gameModelId): ?int 解析 game_ids → 去重/转 int → 调 Model 过滤 → array_rand 返回一个 id

解析规则:

  • 支持 game_ids 为 JSON 数组或逗号分隔字符串(防御性,与部分旧配置风格兼容)。
  • 非法/非正整数丢弃。

2. Model候选池与渠道上架交集

GameApiModel 增加查询方法,例如:

public static function publishedGameIds(int $gameModelId, array $gameIds): array

条件:game_id IN (...)game_model_id = $gameModelIdstatus = STATUS_ON;返回可用 game_id 列表。

不在 Logic 里直接拼 SQL符合分层规则。

3. 改动领取分支

ActivityConfigEntity::receive()ACTIVITY_TYPE_REG case

  • 发奖逻辑保持不变(WalletService::gift + sendRegisterGiftWagerTask + setActivityFinishById)。
  • 仅在 $res 非空(领取成功)后
    • $this->where('id', $activityId)->find() 读取原始 ext_configgetActivityByInfo()getGiftItemsByActivity 组装,不含 ext_config与兑换码分支读库方式一致
    • $gameModelId = $this->_modelId(已由 setSource 设置)。
    • 调用 RegisterRewardLogic::pickRandomGameId()
  • 在方法末尾统一组装返回:有值则追加 'game_id' => $pickedId

GiftController::receive() 补充 PHPDocdata.game_idint可选领取注册活动成功且配置了有效候选池时返回

4. 响应示例

成功且命中游戏:

{
  "code": 0,
  "data": {
    "gift_coin": "10.00",
    "gift_bonus": "0.00",
    "game_id": 205
  }
}

成功但无可用游戏:仅 gift_coin / gift_bonus(与现网兼容)。

单测

新建 slot_console/tests/Unit/RegisterRewardLogicTest.php

  • game_ids 为空 / 缺失 → null
  • 字符串 "1,2,3" 解析
  • Model 层可用 stub 或 sqlite/内存 mock若项目已有 GameApi 测试惯例则对齐)

在 docker 内执行:

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

-- 示例:在现有 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 预展示候选游戏(非领取必需)