--- name: 注册活动推荐游戏配置 overview: 在 slot_admin 活动管理 type=7 编辑页增加「推荐游戏」多选,写入 ext_config.game_ids;配套列表展示与保存校验,与 slot_console 已实现的领取随机进游戏逻辑对齐。 todos: - id: admin-model-api content: GameApiModel 查询方法 + ActivityController::publishedGames status: completed - id: admin-validate content: ActivityValidate::checkRegisterRewardExt + save/update 调用 status: completed - id: vue-edit content: activity/edit.vue type=7 推荐游戏多选与 submit/setFormData status: completed - id: vue-api-index content: activity.js API + index.vue type=7 列表展示 status: completed - id: manual-verify content: 后台保存后 C 端领取验证 game_id 随机返回 status: completed isProject: false --- # 注册活动 type=7 推荐游戏后台配置 ## 背景 C 端已在 [`RegisterRewardLogic`](slot_console/app/api/logic/RegisterRewardLogic.php) 读取 `ext_config.game_ids`,领取注册活动成功后随机返回 `game_id`。本任务补齐 **后台配置入口**,范围: - [`backend/slot_admin_vue`](backend/slot_admin_vue) 活动编辑/列表 - [`backend/slot_admin`](backend/slot_admin) 保存校验与游戏选项 API 不涉及 slot_console 改动(`updateConfig` 已原样持久化 `ext_config` JSON)。 ## 配置契约(与 C 端一致) ```json { "game_ids": [101, 205, 308] } ``` - 值为 `game.id`(`s_game_api.game_id`),须属于活动 `model_id` 下 **status=1** 的已发布游戏。 - 允许为空:领取仍成功,响应不含 `game_id`。 ## 数据流 ```mermaid sequenceDiagram AdminVue->>ActivityController: GET publishedGames?model_id= ActivityController->>GameApiModel: 已上架 game_id 列表 AdminVue->>ActivityController: POST save/update ext_config.game_ids ActivityController->>ActivityValidate: checkRegisterRewardExt ActivityController->>ConsoleInnerapi: ActivityService add/update ConsoleInnerapi->>DB: s_recharge_gift_config.ext_config ``` ## 1. slot_admin 后端 ### 1.1 游戏选项 API 在 [`ActivityController`](backend/slot_admin/app/game/controller/ActivityController.php) 新增: - **`publishedGames(Request $request)`** - 入参:`model_id`(必填,对应活动「游戏模型」) - 出参:`[{ game_id, name }]`,供多选下拉 查询放在 [`GameApiModel`](backend/slot_admin/app/model/GameApiModel.php)(`s_common.s_game_api`): ```php public static function optionsByGameModelId(int $gameModelId): array ``` 条件:`game_model_id`、`status = 1`,`field('game_id,name')`,按 `sort` 排序;可对 `game_id` `group` 去重(与 console 侧一致)。 ### 1.2 保存校验 在 [`ActivityValidate`](backend/slot_admin/app/game/validate/ActivityValidate.php) 新增 **`checkRegisterRewardExt(array $extConfig, int $gameModelId)`**: | 规则 | 说明 | | --- | --- | | `game_ids` 可选 | 缺失或 `[]` 直接通过 | | 元素为正整数 | 非法 ID 抛 `ValidateException` | | 与渠道一致(推荐) | 调用 `GameApiModel::publishedGameIds($gameModelId, $ids)`(与 console 同名语义),提交 ID 必须全部在已发布集合内,否则提示未上架 ID | 在 `ActivityController::save` / `update`(`updateData` 全量更新时)中,当 `type === 7` 时调用: ```php $this->validate->checkRegisterRewardExt( (array) input('ext_config', []), (int) input('model_id', 0) ); ``` 对齐 type=11 的 [`checkFreeCreditsExt`](backend/slot_admin/app/game/validate/ActivityValidate.php) 调用方式。 可在 `GameApiModel` 复用与 console 相同的 `publishedGameIds` 静态方法(admin 连接 `s_common`,表结构一致)。 ## 2. slot_admin_vue 前端 ### 2.1 API 在 [`src/api/game/activity.js`](backend/slot_admin_vue/src/api/game/activity.js) 增加: ```js publishedGames(params) { return request({ url: '/game/activity/publishedGames', method: 'get', params }) } ``` (路径随 Webman 路由约定:`game/activity/publishedGames`。) ### 2.2 编辑页 type=7 表单项 文件:[`src/views/game/activity/edit.vue`](backend/slot_admin_vue/src/views/game/activity/edit.vue) 在 **仅 type=7** 的 `