--- name: 每日返水活动化改造 overview: 将每日返水从独立档位表方案,改为与首充定格(Free Credits, type=11)一致的活动配置模式:新增活动类型 12、档位写入 recharge_gift_config.ext_config,保留 daily_rebate_record 做用户日统计与领取,综合统计页独立不变。 todos: - id: activity-type-12 content: 新增 TYPE_DAILY_REBATE=12:RechargeGiftConfigModel、getDailyRebateActiveInfo、Consts、activity_type 字典 SQL status: completed - id: activity-ext-config content: ActivityValidate::checkDailyRebateExt + ActivityController save/update;activity/edit.vue & index.vue type=12 档位 UI status: completed - id: refactor-daily-rebate-service content: DailyRebateService 改读 recharge_gift_config.ext_config;daily_rebate_record 增加 activity_id status: completed - id: remove-tier-table content: 删除 daily_rebate_tier_config 及相关 Admin CRUD/菜单;更新 daily_rebate.sql status: completed - id: complete-stats-api content: 补全 dailyRebateStats 前端页 + 确认 DailyRebateSettle/Expire/API/流水类型 65 status: completed - id: tests-acceptance content: DailyRebateCalcServiceTest + 端到端验收(配置→结算→领取→统计) status: completed isProject: false --- # 每日返水 — 活动化改造方案(对齐首充定格) ## 背景与纠偏 你已指出:**这是活动,应新增活动类型,返水档位在「活动配置」里维护**,参考首充定格(Free Credits)。 现有代码库中首充定格模式: | 层级 | 实现 | |------|------| | 配置表 | [`s_recharge_gift_config`](slot_console/app/model/common/RechargeGiftConfigModel.php)(后台称「充值活动配置」) | | 活动类型 | `TYPE_FREE_CREDITS = 11` | | 业务参数 | `ext_config` JSON(千分位 `_qf` 字段) | | 后台入口 | [活动管理 → 充值活动配置](backend/slot_admin_vue/src/views/game/activity/index.vue) + [edit.vue type==11 表单项](backend/slot_admin_vue/src/views/game/activity/edit.vue) | | 校验 | [`ActivityValidate::checkFreeCreditsExt`](backend/slot_admin/app/game/validate/ActivityValidate.php) + [`ActivityController::save/update`](backend/slot_admin/app/game/controller/ActivityController.php) | | 运行时查询 | [`RechargeGiftConfigModel::getFreeCreditsActiveInfo`](slot_console/app/model/common/RechargeGiftConfigModel.php) | | 用户状态 | 独立表 `free_credits_player` / `free_credits_package` | **先前中断实现的问题**:已创建 [`daily_rebate_tier_config`](slot_console/db/daily_rebate.sql) 独立表及 [`DailyRebateTierConfig*`](backend/slot_admin/app/game/controller/DailyRebateTierConfigController.php) 后台 — **与产品约定不符,应废弃并改为 ext_config**。 **可保留部分**(逻辑正确,仅需改配置来源): - [`DailyRebateCalcService`](slot_console/app/service/DailyRebateCalcService.php) — 累进分段计算 - [`daily_rebate_record`](slot_console/db/daily_rebate.sql) — 用户日返水记录(需加 `activity_id`) - [`DailyRebateSettle` / `DailyRebateExpire`](slot_console/app/command/DailyRebateSettle.php) 定时任务 - [`DailyRebateController`](slot_console/app/api/controller/DailyRebateController.php) C 端 info/claim - [`DailyRebateStats*`](backend/slot_admin/app/game/controller/DailyRebateStatsController.php) — **综合统计/每日返水统计**(独立菜单,同 Free Credits 统计) ```mermaid flowchart TB subgraph admin [活动管理 slot_admin] ActivityUI["activity/edit.vue type=12"] ActivityAPI["ActivityController + ActivityService"] end subgraph config [s_common] RGC["recharge_gift_config ext_config.tiers"] DRR["daily_rebate_record"] end subgraph runtime [slot_console] Settle["dailyRebateSettle"] API["DailyRebateService info/claim"] end ActivityUI --> ActivityAPI --> RGC Settle --> RGC Settle --> DRR API --> RGC API --> DRR ``` --- ## 1. 新增活动类型 `12` — 每日返水 ### 1.1 常量与模型 - [`RechargeGiftConfigModel`](slot_console/app/model/common/RechargeGiftConfigModel.php) 增加: ```php const TYPE_DAILY_REBATE = 12; // 每日返水 ``` - 新增方法 `getDailyRebateActiveInfo(string $source)`,逻辑**复制** `getFreeCreditsActiveInfo`:`status=1`、`type=12`、时间窗、`source` 优先于 `all`。 - [`slot_lib/Consts.php`](slot_lib/src/common/const/Consts.php) 增加 `ACTIVITY_TYPE_DAILY_REBATE = 12`(与现有 1–9 并列,便于订单/日志引用)。 - 字典 `activity_type` 增加一条(SQL 或后台字典):`value=12, label=每日返水`(与 type=11「首充定格/Free Credits」同级)。 ### 1.2 `ext_config` 结构(档位配置) ```json { "tiers": [ { "sort": 1, "min_bet_qf": 0, "max_bet_qf": 1000000, "rate_percent": 3 }, { "sort": 2, "min_bet_qf": 1000001, "max_bet_qf": 3000000, "rate_percent": 2 }, { "sort": 3, "min_bet_qf": 3000001, "max_bet_qf": 5000000, "rate_percent": 1 }, { "sort": 4, "min_bet_qf": 5000001, "max_bet_qf": null, "rate_percent": 0.5 } ] } ``` - 金额与全站一致:**存储千分位(厘)**;后台表单用美元展示,提交时 `×1000`(与 type=11 的 `toQf` 一致)。 - 默认种子:可在活动保存时由前端预填 4 档,或提供 migration 插入一条 `type=12` 的 default 活动(`source=all`)。 ### 1.3 校验 在 [`ActivityValidate`](backend/slot_admin/app/game/validate/ActivityValidate.php) 新增 `checkDailyRebateExt(array $extConfig)`: - `tiers` 非空数组,每档含 `sort/min_bet_qf/rate_percent`;非最后一档 `max_bet_qf` 必填。 - 复用 [`DailyRebateCalcService::validateTiersContinuous`](slot_console/app/service/DailyRebateCalcService.php)(入参转为 `min_bet`/`max_bet` 厘)。 在 [`ActivityController`](backend/slot_admin/app/game/controller/ActivityController.php) 的 `save` / `update`(`updateData` 时)对 `type === 12` 调用该校验(与 type=11 并列)。 --- ## 2. 管理后台 — 活动配置 UI(核心) 参考 type=11,在 [`activity/edit.vue`](backend/slot_admin_vue/src/views/game/activity/edit.vue) 增加 **`formData.type == 12`** 区块: | 表单项 | 说明 | |--------|------| | 返水档位表 | 可增删行:排序、下限($)、上限($,最后一档可空)、比例(%) | | 规则说明 | 复用活动主表 `help` 字段(与 Free Credits 一致) | | 展示时间/生效时间 | 复用现有 `show_*` / `start_time` / `end_time` | **交互约束**(与 type=11 相同): - `onlyGift` 计算属性加入 `12` → 不展示「赠送配置 goods」区块。 - `submit` 时:`type===12` → `data.goods=[]`,`ext_config.tiers` 做 `toQf` 转换。 - `setFormData` 时:`tiers` 从 `_qf` 还原为美元展示。 [`activity/index.vue`](backend/slot_admin_vue/src/views/game/activity/index.vue) 列表 `ext_config` 列:type=12 时展示各档比例摘要(类似 type=11 展示门槛)。 **删除**(不再单独维护档位): - [`DailyRebateTierConfigController`](backend/slot_admin/app/game/controller/DailyRebateTierConfigController.php) 及 Logic/Validate/Model - [`dailyRebateTierConfig.js`](backend/slot_admin_vue/src/api/game/dailyRebateTierConfig.js) 与对应 vue(若已创建) - [`menu-daily-rebate.sql`](backend/slot_admin/db/menu-daily-rebate.sql) 中「每日返水档位」菜单项(3082) - 表 `daily_rebate_tier_config`(不建或迁移后 DROP) **保留菜单**:仅「综合统计 → 每日返水统计」(3084),挂在活动管理同级或统计分组下。 --- ## 3. 运行时改造(slot_console) ### 3.1 配置读取 改造 [`DailyRebateService`](slot_console/app/service/DailyRebateService.php): - 删除对 `DailyRebateTierConfigModel` 的依赖。 - 通过 `RechargeGiftConfigModel::getDailyRebateActiveInfo($source)` 取活动;无生效活动 → C 端 `unlocked=false` 或整活动不可用(与未开 Free Credits 一致)。 - 从 `ext_config['tiers']` 解析为 `DailyRebateCalcService` 入参(`min_bet`/`max_bet`/`rate_percent`)。 - `info()` 返回的 `tiers` 来自当前活动配置;`tier_snapshot` 结算时写入完整 tiers JSON。 ### 3.2 用户记录表 调整 [`daily_rebate_record`](slot_console/db/daily_rebate.sql): - 增加 `activity_id bigint`(`recharge_gift_config.id`),结算/待定时写入。 - **删除** `daily_rebate_tier_config` 建表与种子 SQL。 ### 3.3 结算与领取 - [`DailyRebateSettle`](slot_console/app/command/DailyRebateSettle.php):按渠道解析活动配置后再算返利;未充值用户仍跳过。 - 领取:继续 `TRANSACTION_TYPE_DAILY_REBATE = 65`(已在 [`Consts.php`](slot_lib/src/common/const/Consts.php) 规划/部分落地)。 ### 3.4 C 端 API(不变路径) - `GET /api/daily-rebate/info` - `POST /api/daily-rebate/claim` 需校验:**当前用户渠道存在生效的 type=12 活动**,否则返回活动未开启。 --- ## 4. 综合统计页(保持独立) 与 [Free Credits 统计](backend/slot_admin/app/game/controller/FreeCreditsStatsController.php) 相同定位: - 菜单:**综合统计 / 每日返水统计**(非活动配置页) - 实现:沿用已规划的 [`DailyRebateStatsLogic`](backend/slot_admin/app/game/logic/DailyRebateStatsLogic.php) + [`dailyRebateStats/index.vue`](backend/slot_admin_vue/src/views/game/dailyRebateStats/index.vue)(若 vue 未写完则补全) - 数据源:`daily_rebate_record`;筛选/汇总规则不变 --- ## 5. 与首充定格的差异对照 | 项 | Free Credits (11) | 每日返水 (12) | |----|-------------------|---------------| | ext_config | 门槛、分档金额、Banner | **tiers 累进档位** | | 用户状态表 | free_credits_player/package | daily_rebate_record | | 统计页 | Free Credits 统计 | 每日返水统计 | | 充值门槛 | 首充定格业务 | **历史充值过即可**(wallet `r>0`) | | 计费基础 | 定格池 | 当日 `user_profit_daily.bet` | --- ## 6. 实施步骤(建议顺序) 1. **活动类型与 ext_config 契约**:Model 常量 + `getDailyRebateActiveInfo` + ActivityValidate + ActivityController + 字典 SQL。 2. **后台 activity/edit.vue + index.vue**:type=12 档位表 UI 与 qf 换算。 3. **重构 DailyRebateService**:读活动 ext_config;record 加 `activity_id`。 4. **清理**:移除 tier 独立表/Controller/菜单;更新 `daily_rebate.sql`。 5. **补全**:统计 vue、PWA 流水类型 65、单元测试仍用 tiers 数组驱动 CalcService。 6. **验收**:后台新建 type=12 活动 → 用户下注 → 日切结算 → 领取 → 统计页数字一致。 --- ## 7. 验收要点 1. 仅在「充值活动配置」可创建/编辑 type=12,档位保存后 `ext_config.tiers` 正确落库。 2. 同渠道多条 type=12 时行为与 type=11 一致(优先具体 source)。 3. 改档位仅影响**新结算日**(`tier_snapshot` 审计旧记录)。 4. 不再出现「每日返水档位」独立菜单。 5. $2000 下注 → 次日返水 $50,与累进公式一致。 --- ## Definition of Done(硬规则对齐) - [ ] `grep -r DailyRebateService ~/Documents/project/www/slot --include='*.php'` → 无命中(排除 vendor) - [ ] [`DailyRebateController`](slot_console/app/api/controller/DailyRebateController.php) 对齐 [`FreeCreditsController`](slot_console/app/api/controller/FreeCreditsController.php)(`BaseController` + Logic + Validate) - [ ] 已删除 orphan:`slot_admin_vue` 下 `dailyRebateTierConfig/*`、`api/game/dailyRebateTierConfig.js` - [ ] `~/.cursor/hooks/verify-slot-backend.sh` 输出 `PASS`