--- name: 移除 pending popup 表 overview: 移除 Lucky Rewards 转盘邀请人 Claim Now 弹窗对 `user_pending_popup` 的依赖,改为在 HomeEvent 中根据 `lucky_reward_player.pending_spin_count > 0` 动态构建弹窗;未领取前每次回大厅重复展示,直至 `claim-inviter-spin` 清零。 todos: - id: build-inviter-popup content: LuckyRewardInviteLogic 新增 buildInviterClaimNowPopup(),删除 notifyInviterInviteSuccess/enqueue status: completed - id: home-event-simplify content: HomeEvent 改用 buildInviterClaimNowPopup,移除 PendingPopupService status: completed - id: remove-pending-popup-infra content: 删除 PendingPopupService/Model/DTO/Entity 及 deploy DDL 引用 status: completed - id: update-tests-docs content: 更新集成测、需求文档与 lucky_reward_deploy 冒烟说明 status: completed isProject: false --- # 移除 user_pending_popup,改用 pending_spin_count 驱动转盘弹窗 ## 背景与结论 当前邀请人「Claim Now」弹窗存在**双源**: ```mermaid sequenceDiagram participant InviteBind as invite_bind participant Player as lucky_reward_player participant Grant as lucky_reward_spin_grant participant Popup as user_pending_popup participant Home as HomeEvent InviteBind->>Grant: 写 invite_inviter grant InviteBind->>Player: pending_spin_count += N InviteBind->>Popup: enqueue lr_invite:{cycle}:{invitee} Home->>Popup: fetchPending + consume Home->>Player: resolvePendingSpinCount 注入 payload ``` - [`LuckyRewardInviteLogic::notifyInviterInviteSuccess()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 入队 `user_pending_popup` - [`HomeEvent::appendLuckyRewardHomePopups()`](slot_console/app/command/event/HomeEvent.php) 再读 `pending_spin_count` 注入 payload **全仓库检索结果**:`PendingPopupService` / `user_pending_popup` **仅被 Lucky Rewards 使用**,无其它业务消费者。可以按你的要求移除该表及相关代码,改以 player 表为唯一触发源。 你已确认弹窗行为:**`pending_spin_count > 0` 时每次回大厅都弹,直到 `claim-inviter-spin` 领完**(比旧「consume 后不再弹」更符合待领语义)。 --- ## 目标行为 | 场景 | 是否弹 Claim Now | 数据来源 | | --- | --- | --- | | `pending_spin_count > 0` | 是,每次 HomeEvent flush | [`resolvePendingSpinCount()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) | | 领取后 `pending_spin_count = 0` | 否 | claim 流程已有扣减 | | `inviter_spin_reward = 0` | 否(无待领 Spin) | 与 grant 逻辑一致 | | 多次邀请、多笔待领 | **一条**弹窗,`pending_spin_count` 为累计值;被邀请人信息取**最早未领** grant | [`findUnclaimedInviterGrant()`](slot_console/app/model/common/LuckyRewardSpinGrantModel.php) + 解析 `biz_id` `invite_inviter:{cycle_id}:{invitee_uid}` | 弹窗 payload 保持与现网客户端兼容(`type: lucky_reward_invite_success`): ```json { "type": "lucky_reward_invite_success", "data": { "invitee_uid": 200001, "invitee_nickname": "Alice", "invitee_avatar": "3", "spin_reward": 1, "cycle_id": 34, "pending_spin_count": 2, "title": "LUCKY YOU!", "content": "You've received 1 Free Spin", "button_text": "Claim Now", "priority": 50 } } ``` - `spin_reward`:当前最早未领 grant 的 `spin_count`(通常 1) - `pending_spin_count`:player 累计待领总数(已有 [`resolvePendingSpinCount()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)) Support Invite(被邀请人)弹窗**不变**,仍走 [`buildSupportInvitePopup()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) + `ensureInviteeAutoOpenBox()`。 --- ## 代码改动 ### 1. 新增邀请人弹窗构建方法 在 [`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 增加 public 方法,例如 `buildInviterClaimNowPopup(int $uid, string $source): array|false`: - 活动关闭 / 无有效轮次 → `false` - `resolvePendingSpinCount($uid, $source) <= 0` → `false` - 取 `findUnclaimedInviterGrant($uid, $cycleId)`;若 grant 为空但 count>0(脏数据)→ 打 error 日志并 `false` - 从 grant `biz_id` 解析 `invitee_uid`,`fetchUserProfile()` 取昵称/头像 - 返回与现网一致的 `type` + `data` 结构 ### 2. 简化 HomeEvent [`HomeEvent::appendLuckyRewardHomePopups()`](slot_console/app/command/event/HomeEvent.php): - 删除 `PendingPopupService` 引用及 `fetchPending` / `consume` 循环 - 在 Support Invite 之后调用 `buildInviterClaimNowPopup()`,有则 `$luckyRewardPopups[]` 追加 - `pending_spin_count` 已在 popup data 内组装,无需二次注入 ### 3. 删除 invite_bind 入队逻辑 [`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php): - 删除 `notifyInviterInviteSuccess()` 及对 `PendingPopupService::enqueue` 的调用(`handleInviteBind` 第 108 行) - 移除 `PendingPopupService` / `PendingPopupEnqueueDTO` 依赖 - `InviteBindProcessContextDTO::$popupBizId` 若仅用于 popup,可一并删除(保留 `inviterBizId` 供 grant 幂等) ### 4. 移除 pending popup 基础设施(无其它引用) 删除 slot_console 内: - [`app/service/PendingPopupService.php`](slot_console/app/service/PendingPopupService.php) - [`app/model/common/UserPendingPopupModel.php`](slot_console/app/model/common/UserPendingPopupModel.php) - [`app/dto/pendingPopup/PendingPopupEnqueueDTO.php`](slot_console/app/dto/pendingPopup/PendingPopupEnqueueDTO.php) - [`app/entity/pendingPopup/*`](slot_console/app/entity/pendingPopup/) DDL / 部署文档: - [`backend/slot_admin/db/user_pending_popup.sql`](backend/slot_admin/db/user_pending_popup.sql) 标记废弃或删除 - 可选新增 `backend/slot_admin/db/user_pending_popup_drop.sql`(`DROP TABLE IF EXISTS user_pending_popup`)供已部署环境执行 - 更新 [`slot_console/doc/lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 部署步骤(去掉第 2 步建表) ### 5. 测试 更新 [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php): - 删除对 `UserPendingPopupModel` 的断言(约 61–78、96–99 行) - 新增用例:`buildInviterClaimNowPopup` 在 bind 后返回非 false,且含 `pending_spin_count`;`claimInviterSpin` 后返回 false 更新 [`LuckyRewardDbTestCase`](slot_console/tests/Integration/LuckyRewardDbTestCase.php): - 去掉 `user_pending_popup` 表存在性检查与 cleanup 可选:新增单元测覆盖 `buildInviterClaimNowPopup` 的 grant biz_id 解析(mock 较少时可放集成测)。 ### 6. 文档 - [`docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §5:Claim Now 改为 `pending_spin_count > 0` + `buildInviterClaimNowPopup` - [`docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md`](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md):标注 Lucky Rewards 已不再使用通用表;若整表无其它用途则机制废弃 - [`lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 冒烟:邀请人回大厅见 Claim Now(可重复至领取) --- ## 行为差异说明(验收时注意) | 项 | 旧(user_pending_popup) | 新(pending_spin_count) | | --- | --- | --- | | 未点 Claim 再次回大厅 | 不再弹(已 consume) | **继续弹**(你已确认) | | 多笔邀请 | 可能多条 popup 队列 | **一条**,count 累计 | | inviter_spin_reward=0 | 仍入队通知 | **不弹**(count 为 0) | --- ## 验收清单 1. invite_bind success → `pending_spin_count` 增加,**不写** `user_pending_popup` 2. 邀请人 HomeEvent → popList 含 `lucky_reward_invite_success`,`pending_spin_count` 正确 3. 未 claim 前多次回大厅 → 弹窗仍出现 4. `POST claim-inviter-spin` 后 → `pending_spin_count=0`,弹窗不再出现 5. 被邀请人 Support Invite + auto openBox 不受影响 6. `RUN_DB_TESTS=1` 集成测通过;verify + php -l PASS