This commit is contained in:
ray zhou
2026-06-29 14:51:55 +08:00
parent 225fb2bd28
commit 2dd9f17da9
319 changed files with 29461 additions and 9412 deletions

View File

@@ -0,0 +1,212 @@
---
name: Lucky Reward 奖池迁移
overview: 采用全平台统一的 reward_pool / reward_pool_item以 pool_code = lucky_reward 承载大转盘手动 Spin 奖项;外层仅 prize_type 表达类型lucky_reward 业务参数(含 unlockInviteCount一律进 config逐步替换 lucky_reward_prize_config。
todos:
- id: ddl-seed
content: s_common 建 reward_pool / reward_pool_item含 prize_type 外层字段seed pool_code=lucky_reward编写从 lucky_reward_prize_config 的迁移脚本
status: completed
- id: console-draw
content: slot_consoleRewardPoolItemModel + ConfigService/DrawService/LuckyRewardLogic 改读 lucky_reward 奖池Draw 读 prize_type 列
status: completed
- id: admin-crud
content: slot_admin替换 LuckyRewardPrizeConfig CRUD 为 lucky_reward 奖池项管理,更新菜单权限
status: completed
- id: test-docs-cleanup
content: 单测/集成测、需求文档更新、删除旧 Model 与 lucky_reward_prize_config 表
status: completed
isProject: false
---
# Lucky Reward 奖池方案评估与迁移计划
## 结论:`pool_code = lucky_reward` 可行,推荐做
**方向正确**:把「可复用奖池」与「活动专用抽奖/入账」拆开,比继续扩 [`lucky_reward_prize_config`](docs/requirements/lucky_rewards/02_管理后台方案.md) 更适合后续其它活动复用同一套表结构。
**与你已确认的前提对齐**
- 全平台 **一个** 奖池:`pool_code = 'lucky_reward'`
- **替换** 现有 [`lucky_reward_prize_config`](slot_console/app/model/common/LuckyRewardPrizeConfigModel.php)(非并存长期双写)
- **外层仅 `prize_type` 表达奖项类型**lucky_reward 业务参数(含开放条件)**一律进 `config`**,避免个别字段外置导致表结构膨胀
```mermaid
flowchart LR
subgraph admin [slot_admin]
PoolCRUD[RewardPoolItem CRUD]
end
subgraph db [s_common]
RP[reward_pool pool_code=lucky_reward]
RPI["reward_pool_item prize_type + config"]
end
subgraph console [slot_console]
Draw[LuckyRewardDrawService]
Spin[LuckyRewardLogic.executeManualSpin]
end
PoolCRUD --> RPI
RP --> RPI
RPI --> Draw
Draw --> Spin
```
---
## 核心设计:`prize_type` 外层 + 业务参数全进 `config`
**字段分层原则**
| 层级 | 字段 | 说明 |
| --- | --- | --- |
| 表通用列 | `pool_id``pool_code``item_code``item_name``prize_type``weight``display_text``icon_url``status``sort` | 奖池项元数据,各 pool 共用 |
| `config` JSON | lucky_reward 及后续各 pool 的**业务参数** | 含开放条件、金额区间等;**禁止**再拆个别业务字段到表列 |
| 禁止 | 表列 `unlock_invite_count` 等 lucky_reward 专用字段 | 与「通用奖池表 + pool 级 config 约定」冲突 |
### 1. 表字段调整(相对你初版 DDL
原 DDL 中的 `reward_type` **改为 `prize_type`**TINYINT奖项命中语义。不同 `pool_code` 可约定不同枚举;`lucky_reward` 池定义如下:
| prize_type | 含义 | 抽奖 | 入账行为(与现网一致) |
| --- | --- | --- | --- |
| 1 | 随机金额 | 参与权重 | My Amount 增加(封顶至 target |
| 2 | 1x Spin | 参与权重 | spin_available +1 |
| 3 | Cash Out | 参与权重 | playerStatus → 可提取 |
| 4 | Jackpot 展示 | **不参与**weight=0 或 Draw 过滤) | 无入账,仅转盘 UI 展示 |
常量命名沿用现有 [`LuckyRewardPrizeConfigModel::PRIZE_TYPE_*`](slot_console/app/model/common/LuckyRewardPrizeConfigModel.php),迁移到 `RewardPoolItemModel`(或共用常量类),保证 [`lucky_reward_spin_record.prize_type`](docs/requirements/lucky_rewards/02_管理后台方案.md) 与 [`DrawResultEntity::prizeType`](slot_console/app/entity/luckyReward/DrawResultEntity.php) **数值不变**
### 2. `lucky_reward` 池 `config` 结构SSOT
**禁止** config 内写 `prizeType`(类型只看外层列)。按 `prize_type` 校验必填/可选字段admin Validate + 文档):
**各类型共有可选字段**(参与抽奖的类型 1/2/3 常用):
| config 字段 | 说明 |
| --- | --- |
| `unlockInviteCount` | 开放命中所需有效邀请人数,默认 0无需 |
**各类型专有字段**
| prize_type | 专有 config 字段 | 说明 |
| --- | --- | --- |
| 1 随机金额 | `amountMinQf`, `amountMaxQf` | 千分位区间min ≤ max |
| 2 1x Spin | — | 可无专有字段 |
| 3 Cash Out | — | 可无专有字段;开放条件用 `unlockInviteCount` |
| 4 Jackpot | `displayAmountQf` | 展示用金额(千分位) |
示例:
```json
// prize_type = 1需 3 个有效邀请后才开放
{ "unlockInviteCount": 3, "amountMinQf": 100, "amountMaxQf": 500 }
// prize_type = 3Cash Out 需 5 个邀请
{ "unlockInviteCount": 5 }
// prize_type = 4
{ "displayAmountQf": 6666000 }
```
### 3. 外层列(不进 config
仅保留奖池项**通用**列,不含 lucky_reward 业务参数:
| 字段 | 说明 |
| --- | --- |
| `weight` | 抽取权重 |
| `display_text` / `icon_url` / `sort` | 前端展示与排序 |
`reward_pool_item` 建议 DDL 片段(相对初版变更点):
```sql
`prize_type` TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '奖项类型lucky_reward池见 PRIZE_TYPE_* 常量',
`config` JSON NOT NULL COMMENT 'pool 业务参数lucky_reward见文档 SSOT',
-- 删除 reward_type不新增 unlock_invite_count 等 pool 专用列
```
### 4. 全平台单池
所有 source 共用 `pool_code = lucky_reward` 一套转盘格子和权重;[`LuckyRewardConfigService::listEnabledPrizeConfigs($configId)`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php) 改为按 `pool_code` 加载,**不再依赖** `lucky_reward_config.id`
活动 per-source 配置(开关、周期、分层开宝箱、目标金额)不变。
### 5. DDL 其它细节
| 项 | 建议 |
| --- | --- |
| 主键 | 确认 ID 策略:若无雪花发号,补 AUTO_INCREMENT |
| 时间字段 | Model 层映射 `created_at`/`updated_at` |
| 库 | **s_common** |
| 索引 | item 表增加 `KEY idx_pool_code_status (pool_code, status)``KEY idx_prize_type (prize_type)` |
### 6. 常量约定
```php
/** Lucky Rewards 大转盘手动 Spin 奖池编码 */
public const POOL_CODE_LUCKY_REWARD = 'lucky_reward';
```
`prize_type` 常量(中文注释必填)与现网 1/2/3/4 对齐。
---
## 迁移与实现步骤
### Phase 1 — 表结构与数据迁移
1.`s_common` 执行 `reward_pool``reward_pool_item` DDL`prize_type` + `config`,无 `reward_type`、无 `unlock_invite_count` 列)
2. Seed`pool_code = lucky_reward``pool_name = Lucky Rewards Wheel``status = 1`
3. 迁移 `lucky_reward_prize_config``reward_pool_item`
- `prize_type` ← 旧 `prize_type`(直迁)
- `weight``sort``status` 直迁
- `config`:写入 `unlockInviteCount`(← 旧 `unlock_invite_count`+ 类型专有字段amountMinQf/MaxQf 或 displayAmountQf
- `item_code`:建议 `lr_prize_{old_id}`
4. 验证通过后 drop 旧表(或先 rename `_bak`
### Phase 2 — slot_console 读新池抽奖
| 文件 | 变更 |
| --- | --- |
| 新建 `RewardPoolModel` / `RewardPoolItemModel` | `listEnabledByPoolCode()` |
| [`LuckyRewardConfigService`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php) | `listLuckyRewardPoolItems()`,固定 `POOL_CODE_LUCKY_REWARD` |
| [`LuckyRewardDrawService`](slot_console/app/service/luckyReward/LuckyRewardDrawService.php) | 读列 `prize_type`;过滤读 `config.unlockInviteCount`(缺省 0随机金额读 `config.amountMinQf/MaxQf`Jackpot(4) 仍排除 |
| [`DrawResultEntity`](slot_console/app/entity/luckyReward/DrawResultEntity.php) | 增加 `poolItemId``prizeType` 来自 item 的 `prize_type` 列 |
| [`LuckyRewardLogic::executeManualSpin`](slot_console/app/api/logic/LuckyRewardLogic.php) | 切换数据源spin_record.prize_type 仍写 Draw 结果 |
**行为不变**:随机封顶、+1 Spin、Cash Out 改状态、spin_record 写入。
### Phase 3 — slot_admin 后台替换 CRUD
| 现状 | 目标 |
| --- | --- |
| [`LuckyRewardPrizeConfigController`](backend/slot_admin/app/game/controller/LuckyRewardPrizeConfigController.php) 等 | Lucky Reward 奖池项管理scoped `pool_code=lucky_reward` |
| Validate | 校验外层 `prize_type`、按类型校验 config`unlockInviteCount`、金额区间)、权重 |
| [`menu-lucky-rewards.sql`](backend/slot_admin/db/menu-lucky-rewards.sql) | 路由指向新 Controller |
表单:美元展示 → 写入 config 内 `_qf``unlockInviteCount` 表单项写入 config`prize_type` 下拉与现网四类一致。
### Phase 4 — 文档、测试、清理
- 更新 [`02_管理后台方案.md`](docs/requirements/lucky_rewards/02_管理后台方案.md)`reward_pool_item.prize_type` 枚举 + config 结构 SSOT
- 更新 [`LuckyRewardDrawServiceTest`](slot_console/tests/Unit/LuckyRewardDrawServiceTest.php) fixturepool item 含 `prize_type` 列 + 精简 config
- 删除 `LuckyRewardPrizeConfigModel` 及旧表引用
---
## 风险与规避
| 风险 | 规避 |
| --- | --- |
| 运营迁移窗口改旧表 | 迁移前冻结编辑;脚本完成后立即切读新表 |
| Jackpot 无 C 端拉取 | 后台仍配 prize_type=4后续如需动态转盘再补接口 |
| 其它 pool_code 的 prize_type 语义冲突 | 按 pool 文档约定枚举;通用表结构复用,语义由 pool_code + 文档定义 |
| config 误写 prizeType | Validate 拒绝;迁移脚本不写入 prizeType |
| 业务字段外置导致表膨胀 | 约定:除 `prize_type` 外 lucky_reward 参数一律 config其它 pool 同理 |
---
## 总体评价
- **赞成** `pool_code = lucky_reward` 作为大转盘唯一奖池编码。
- **采纳**:类型语义 **外层 `prize_type`****`unlockInviteCount` 等业务参数进 config**,与通用奖池表设计一致。
- 其它活动复用 `reward_pool_item` 时,同一 `prize_type` 数值在不同 pool 可代表不同含义,需在各自 pool 文档中定义lucky_reward 池先用 1/2/3/4 四态)。
确认本计划后,按 Phase 1→4 落地。