213 lines
10 KiB
Markdown
213 lines
10 KiB
Markdown
---
|
||
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_console:RewardPoolItemModel + 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 = 3,Cash 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) fixture:pool 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 落地。
|