13 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 全局活动轮次 | Lucky Rewards 活动配置与轮次均改为全平台唯一:`lucky_reward_config`、`lucky_reward_tier_config`、`lucky_reward_cycle` 移除 `source`;转盘奖项已迁至 `reward_pool_item`(无 source,legacy `lucky_reward_prize_config` 确认删除);C 端仍用 `lucky_reward_player.source` 记录用户注册渠道。 |
|
false |
Lucky Rewards 配置与轮次全局化(不区分渠道)
目标与边界
| 维度 | 变更后 |
|---|---|
lucky_reward_config |
全平台唯一主配置,移除 source 列(表内仅保留一行或业务层强制单例) |
lucky_reward_tier_config |
移除 source 列,仅通过 config_id 关联主配置 |
lucky_reward_prize_config |
已废弃;奖项 SSOT 为 reward_pool + reward_pool_item(pool_code=lucky_reward,本身无 source)。若环境仍残留 legacy 表,执行 DROP,无需对其 ALTER 删列 |
lucky_reward_cycle |
全平台唯一进行中轮次,移除 source 列 |
lucky_reward_player.source 等业务表 |
保留,表示用户注册/归属渠道,供后台统计筛选,与活动配置无关 |
wheel 短码 biz_id=cycle_id |
不变,全渠道共用同一 cycle_id |
flowchart TB
subgraph before [现状]
ConfigA[config source=A]
ConfigB[config source=B]
ConfigA --> CycleA[cycle source=A]
ConfigB --> CycleB[cycle source=B]
end
subgraph after [改造后]
GlobalConfig[单一 lucky_reward_config]
GlobalCycle[单一 active cycle]
PlayerA[player source=渠道A]
PlayerB[player source=渠道B]
GlobalConfig --> GlobalCycle
GlobalCycle --> PlayerA
GlobalCycle --> PlayerB
end
与 00_整体技术方案.md 一致:cycle 表本无 source;配置亦改为全局单套参数。
1. DDL 与数据迁移
新增 backend/slot_admin/db/lucky_reward_drop_source.sql(合并原 cycle 脚本,一次迁移三表):
1.1 lucky_reward_config
-
合并多行配置(若存在按渠道多行)
- 保留
source='default'且status=1的行;若无 default 启用行则保留id最小且status=1的行 - 将其余行的
lucky_reward_tier_config.config_id重指向保留行 - 删除其余 config 行
- 保留
-
改表
DROP INDEX idx_sourceDROP COLUMN source
1.2 lucky_reward_tier_config
DROP COLUMN source(已通过config_id关联,列冗余;admin Tier Logic/Validate 同步去 source 字段)
1.3 lucky_reward_prize_config(legacy)
现状:转盘奖项已迁移至
reward_pool.sql的reward_pool_item,console 通过LuckyRewardConfigService::listLuckyRewardPoolItems()读pool_code=lucky_reward,无渠道维度。
迁移步骤(写入 lucky_reward_drop_source.sql 末尾或独立段落):
- 若
lucky_reward_prize_config表仍存在 且尚未迁移:先跑reward_pool_migrate_lucky_reward_prize.sql(迁移脚本内@config_id改为取合并后的唯一 config 行,不再WHERE source='default') - 验证
reward_pool_item数据完整后,执行reward_pool_drop_legacy_prize_config.sql:DROP TABLE IF EXISTS lucky_reward_prize_config - 无 PHP Model/Logic 改动(已无
LuckyRewardPrizeConfig*代码路径;后台菜单已指向RewardPoolItemController)
文档同步:04_slot_console_活动主流程方案.md 中将 lucky_reward_prize_config 表述改为 reward_pool_item。
1.4 lucky_reward_cycle
- 合并重复
status=1:保留id最大一行,其余改STATUS_ENDED=2(不合并 player 行) DROP INDEX idx_source_status→DROP COLUMN source→ADD KEY idx_status (status)
1.5 同步基线 DDL
backend/slot_admin/db/lucky_reward.sql— config / tier / cycle 去掉source;不包含已废弃的 prize_config 建表docs/requirements/lucky_rewards/02_管理后台方案.md§2.1 / §2.3 / §2.4(去掉「用 source 区分渠道」;§2.2 已说明 prize 在 reward_pool)
2. Model 层
2.1 LuckyRewardConfigModel(console + admin 同步)
- 删除
@property string $source - 删除
findEnabledBySourceWithFallback(string $source) - 新增
findEnabled(): ?self—status=STATUS_ENABLED,order id asc,取唯一启用配置 - admin Model 去掉 search 按 source 的 scope(若有)
2.2 LuckyRewardTierConfigModel
- 删除
@property string $source listEnabledByConfigId(int $configId)不变
2.3 LuckyRewardCycleModel
- 删除
source与findActiveBySource/maxCycleNo(string $source) - 新增
findActive(): ?self、maxCycleNo(): int
3. Service 层(slot_console)
3.1 LuckyRewardConfigService
| 方法 | 改造 |
|---|---|
requireEnabledConfig() |
无参;内部 findEnabled(),未开启抛 BusinessException |
resolveActiveCycle(LuckyRewardConfigModel $activityConfig) |
去掉 $source;查 findActive();创建下一轮调 createNextCycle($activityConfig, ...) |
createNextCycle(LuckyRewardConfigModel $activityConfig, ?int $baseTimestamp = null) |
去掉 $source;cycle_days 直接取自传入的唯一 $activityConfig;不写 cycle.source;事务 + FOR UPDATE 防并发双 active |
3.2 LuckyRewardCycleRolloverService
rolloverExpiredCycle:去掉$expiredCycle->source- 开启下一轮:
findActive()为空且findEnabled()非空时createNextCycle($activityConfig, $nowTimestamp)
4. Logic / 其它调用点(slot_console)
配置读取:所有 findEnabledBySourceWithFallback($resolvedSource) / requireEnabledConfig($source) 改为无参全局读取。
轮次读取:所有 findActiveBySource(...) 改为 findActive()。
仍保留 resolveSource($uid, $source) 的场景(仅写业务行渠道归属,不用于查配置):
lucky_reward_player.sourcelucky_reward_spin_grant.sourcelucky_reward_helper.sourcelucky_reward_spin_record.source- 日志 / MQ 回调
channel_code字段
| 文件 | 改动要点 |
|---|---|
LuckyRewardLogic.php |
enter/spin/openBox/toBalance:配置无参;轮次 findActive();player 写入仍用 $resolvedSource |
LuckyRewardInviteLogic.php |
invite_bind、弹窗、claim:配置/轮次全局;helper/player 仍写用户渠道 |
LuckyRewardSupportInvitePendingService.php |
flush 时查全局 config + active cycle |
ShareService.php |
resolveOrCreateWheelShareRow:requireEnabledConfig() + resolveActiveCycle($config) |
Controller 仍向 Logic 传 $request->userEntity->source(供 player 归属),Logic 内部不再用它查 config。
5. 管理后台(slot_admin)
| 文件 | 改动 |
|---|---|
LuckyRewardConfigLogic |
去掉 source 写入与 ensureSourceUnique;新增 单例校验(全表仅允许 1 行,update 除外) |
LuckyRewardConfigValidate |
save/update scene 移除 source |
LuckyRewardConfigController |
index 去掉 source 筛选;options 返回 id,status(无 source) |
LuckyRewardTierConfigLogic |
去掉 source 写入与列表 config_source 展示 |
LuckyRewardTierConfigValidate |
移除 source |
| Model PHPDoc | Config / Tier / Cycle 三表同步 |
LuckyRewardStatsLogic:不变 — 统计仍可按 lucky_reward_player.source 筛用户渠道。
前端(若 slot_admin_vue 有 Lucky Reward 配置页渠道字段):移除主配置/分层表单中的「渠道」输入与列表列(本计划标注为 admin 联调项,改 PHP 后前端需同步)。
6. 测试
LuckyRewardDbTestCase::seedEnabledActivity:
- 不再按
TEST_SOURCE创建独立 config;改为 更新全局唯一 config 为 ENABLED(或 insert 仅当表空) - cycle seed 不写
source;先findActive()结束旧 active - player / helper 测试行仍可写
source => TEST_SOURCE模拟用户渠道
更新所有集成测试中的 findEnabledBySourceWithFallback / findActiveBySource / config 按 source 查询。
新增用例:两渠道用户(不同 player.source)进入活动,得到相同 config 参数与 cycle_id。
7. 部署顺序
- 执行
lucky_reward_drop_source.sql(合并 config + 删列) - 同批发布 slot_console + slot_admin(删列后旧代码会 SQL 报错)
- slot_admin_vue 去渠道字段(可与后端同批或紧随其后)
8. 风险与验收
| 风险 | 处理 |
|---|---|
| 线上多渠道各有 config / active cycle | 迁移脚本合并为单行 config + 单行 active cycle |
| 非 default 渠道 config 有差异化参数 | 迁移保留 default 启用行;运营需事先确认 default 参数为 SSOT |
| 并发创建双 active cycle | createNextCycle 事务 + 行锁 |
| 后台误建第二条 config | Logic 单例校验拦截 |
验收清单:
- 全渠道用户
enter读到同一套 target_amount / cycle_days / tier - 全渠道同一
cycle_id;轮转后仅一条新 active - 后台主配置 CRUD 无渠道字段,不可新增第二条
- 统计页仍可按 玩家 source 筛选
phpunitLucky Rewards 集成测 +verify-slot-backend.shPASS
涉及文件汇总
DDL:lucky_reward_drop_source.sql、lucky_reward.sql、reward_pool_migrate_lucky_reward_prize.sql(改 config 选取逻辑)、reward_pool_drop_legacy_prize_config.sql、需求文档
slot_console:LuckyRewardConfigModel、LuckyRewardTierConfigModel、LuckyRewardCycleModel、LuckyRewardConfigService、LuckyRewardCycleRolloverService、LuckyRewardLogic、LuckyRewardInviteLogic、LuckyRewardSupportInvitePendingService、ShareService、集成测试
slot_admin:LuckyRewardConfigModel、LuckyRewardTierConfigModel、LuckyRewardCycleModel、LuckyRewardConfigLogic、LuckyRewardTierConfigLogic、对应 Validate/Controller
无需改动(已无 source):reward_pool / reward_pool_item、RewardPoolItemLogic(转盘奖项 CRUD)
保留 source 不改:lucky_reward_player 及 spin/helper/record/grant 业务表;LuckyRewardStatsLogic 玩家渠道筛选